| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1 | /* | 
 | 2 | // Copyright (c) 2018-2019 Intel Corporation | 
 | 3 | // | 
 | 4 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 5 | // you may not use this file except in compliance with the License. | 
 | 6 | // You may obtain a copy of the License at | 
 | 7 | // | 
 | 8 | //      http://www.apache.org/licenses/LICENSE-2.0 | 
 | 9 | // | 
 | 10 | // Unless required by applicable law or agreed to in writing, software | 
 | 11 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 13 | // See the License for the specific language governing permissions and | 
 | 14 | // limitations under the License. | 
 | 15 | */ | 
 | 16 | #include "i2c.hpp" | 
 | 17 |  | 
 | 18 | #include <sys/sysinfo.h> | 
 | 19 | #include <systemd/sd-journal.h> | 
 | 20 |  | 
 | 21 | #include <boost/asio/posix/stream_descriptor.hpp> | 
 | 22 | #include <boost/container/flat_map.hpp> | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 23 | #include <boost/container/flat_set.hpp> | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 24 | #include <gpiod.hpp> | 
| Vijay Khemka | fc1ecc5 | 2020-04-01 10:49:28 -0700 | [diff] [blame] | 25 | #include <phosphor-logging/log.hpp> | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 26 | #include <sdbusplus/asio/object_server.hpp> | 
| Vijay Khemka | 2b6f442 | 2020-05-29 11:13:23 -0700 | [diff] [blame] | 27 |  | 
 | 28 | #include <filesystem> | 
 | 29 | #include <fstream> | 
 | 30 | #include <iostream> | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 31 | #include <string_view> | 
 | 32 |  | 
 | 33 | namespace power_control | 
 | 34 | { | 
 | 35 | static boost::asio::io_service io; | 
 | 36 | std::shared_ptr<sdbusplus::asio::connection> conn; | 
 | 37 | static std::shared_ptr<sdbusplus::asio::dbus_interface> hostIface; | 
 | 38 | static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisIface; | 
| Vijay Khemka | 75ad0cf | 2020-04-02 15:23:51 -0700 | [diff] [blame] | 39 | static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSysIface; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 40 | static std::shared_ptr<sdbusplus::asio::dbus_interface> powerButtonIface; | 
 | 41 | static std::shared_ptr<sdbusplus::asio::dbus_interface> resetButtonIface; | 
 | 42 | static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiButtonIface; | 
 | 43 | static std::shared_ptr<sdbusplus::asio::dbus_interface> osIface; | 
 | 44 | static std::shared_ptr<sdbusplus::asio::dbus_interface> idButtonIface; | 
| Chen Yugang | 174ec66 | 2019-08-19 19:58:49 +0800 | [diff] [blame] | 45 | static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiOutIface; | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 46 | static std::shared_ptr<sdbusplus::asio::dbus_interface> restartCauseIface; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 47 |  | 
 | 48 | static gpiod::line powerButtonMask; | 
 | 49 | static gpiod::line resetButtonMask; | 
 | 50 | static bool nmiButtonMasked = false; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 51 |  | 
 | 52 | const static constexpr int powerPulseTimeMs = 200; | 
 | 53 | const static constexpr int forceOffPulseTimeMs = 15000; | 
 | 54 | const static constexpr int resetPulseTimeMs = 500; | 
| Jason M. Bills | fc9408a | 2020-01-31 14:54:17 -0800 | [diff] [blame] | 55 | const static constexpr int powerCycleTimeMs = 5000; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 56 | const static constexpr int sioPowerGoodWatchdogTimeMs = 1000; | 
 | 57 | const static constexpr int psPowerOKWatchdogTimeMs = 8000; | 
 | 58 | const static constexpr int gracefulPowerOffTimeMs = 60000; | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 59 | const static constexpr int warmResetCheckTimeMs = 500; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 60 | const static constexpr int buttonMaskTimeMs = 60000; | 
 | 61 | const static constexpr int powerOffSaveTimeMs = 7000; | 
 | 62 |  | 
 | 63 | const static std::filesystem::path powerControlDir = "/var/lib/power-control"; | 
 | 64 | const static constexpr std::string_view powerStateFile = "power-state"; | 
 | 65 |  | 
 | 66 | static bool nmiEnabled = true; | 
 | 67 | static constexpr const char* nmiOutName = "NMI_OUT"; | 
| Vijay Khemka | 0dc7d4c | 2019-10-22 12:30:17 -0700 | [diff] [blame] | 68 | static constexpr const char* powerOutName = "POWER_OUT"; | 
 | 69 | static constexpr const char* resetOutName = "RESET_OUT"; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 70 |  | 
 | 71 | // Timers | 
 | 72 | // Time holding GPIOs asserted | 
 | 73 | static boost::asio::steady_timer gpioAssertTimer(io); | 
 | 74 | // Time between off and on during a power cycle | 
 | 75 | static boost::asio::steady_timer powerCycleTimer(io); | 
 | 76 | // Time OS gracefully powering off | 
 | 77 | static boost::asio::steady_timer gracefulPowerOffTimer(io); | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 78 | // Time the warm reset check | 
 | 79 | static boost::asio::steady_timer warmResetCheckTimer(io); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 80 | // Time power supply power OK assertion on power-on | 
 | 81 | static boost::asio::steady_timer psPowerOKWatchdogTimer(io); | 
 | 82 | // Time SIO power good assertion on power-on | 
 | 83 | static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io); | 
 | 84 | // Time power-off state save for power loss tracking | 
 | 85 | static boost::asio::steady_timer powerStateSaveTimer(io); | 
 | 86 | // POH timer | 
 | 87 | static boost::asio::steady_timer pohCounterTimer(io); | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 88 | // Time when to allow restart cause updates | 
 | 89 | static boost::asio::steady_timer restartCauseTimer(io); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 90 |  | 
 | 91 | // GPIO Lines and Event Descriptors | 
 | 92 | static gpiod::line psPowerOKLine; | 
 | 93 | static boost::asio::posix::stream_descriptor psPowerOKEvent(io); | 
 | 94 | static gpiod::line sioPowerGoodLine; | 
 | 95 | static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io); | 
 | 96 | static gpiod::line sioOnControlLine; | 
 | 97 | static boost::asio::posix::stream_descriptor sioOnControlEvent(io); | 
 | 98 | static gpiod::line sioS5Line; | 
 | 99 | static boost::asio::posix::stream_descriptor sioS5Event(io); | 
 | 100 | static gpiod::line powerButtonLine; | 
 | 101 | static boost::asio::posix::stream_descriptor powerButtonEvent(io); | 
 | 102 | static gpiod::line resetButtonLine; | 
 | 103 | static boost::asio::posix::stream_descriptor resetButtonEvent(io); | 
 | 104 | static gpiod::line nmiButtonLine; | 
 | 105 | static boost::asio::posix::stream_descriptor nmiButtonEvent(io); | 
 | 106 | static gpiod::line idButtonLine; | 
 | 107 | static boost::asio::posix::stream_descriptor idButtonEvent(io); | 
 | 108 | static gpiod::line postCompleteLine; | 
 | 109 | static boost::asio::posix::stream_descriptor postCompleteEvent(io); | 
 | 110 | static gpiod::line nmiOutLine; | 
 | 111 |  | 
 | 112 | static constexpr uint8_t beepPowerFail = 8; | 
 | 113 |  | 
 | 114 | static void beep(const uint8_t& beepPriority) | 
 | 115 | { | 
 | 116 |     std::cerr << "Beep with priority: " << (unsigned)beepPriority << "\n"; | 
 | 117 |  | 
 | 118 |     conn->async_method_call( | 
 | 119 |         [](boost::system::error_code ec) { | 
 | 120 |             if (ec) | 
 | 121 |             { | 
 | 122 |                 std::cerr << "beep returned error with " | 
 | 123 |                              "async_method_call (ec = " | 
 | 124 |                           << ec << ")\n"; | 
 | 125 |                 return; | 
 | 126 |             } | 
 | 127 |         }, | 
 | 128 |         "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode", | 
 | 129 |         "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority)); | 
 | 130 | } | 
 | 131 |  | 
 | 132 | enum class PowerState | 
 | 133 | { | 
 | 134 |     on, | 
 | 135 |     waitForPSPowerOK, | 
 | 136 |     waitForSIOPowerGood, | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 137 |     off, | 
 | 138 |     transitionToOff, | 
 | 139 |     gracefulTransitionToOff, | 
 | 140 |     cycleOff, | 
 | 141 |     transitionToCycleOff, | 
 | 142 |     gracefulTransitionToCycleOff, | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 143 |     checkForWarmReset, | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 144 | }; | 
 | 145 | static PowerState powerState; | 
 | 146 | static std::string getPowerStateName(PowerState state) | 
 | 147 | { | 
 | 148 |     switch (state) | 
 | 149 |     { | 
 | 150 |         case PowerState::on: | 
 | 151 |             return "On"; | 
 | 152 |             break; | 
 | 153 |         case PowerState::waitForPSPowerOK: | 
 | 154 |             return "Wait for Power Supply Power OK"; | 
 | 155 |             break; | 
 | 156 |         case PowerState::waitForSIOPowerGood: | 
 | 157 |             return "Wait for SIO Power Good"; | 
 | 158 |             break; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 159 |         case PowerState::off: | 
 | 160 |             return "Off"; | 
 | 161 |             break; | 
 | 162 |         case PowerState::transitionToOff: | 
 | 163 |             return "Transition to Off"; | 
 | 164 |             break; | 
 | 165 |         case PowerState::gracefulTransitionToOff: | 
 | 166 |             return "Graceful Transition to Off"; | 
 | 167 |             break; | 
 | 168 |         case PowerState::cycleOff: | 
 | 169 |             return "Power Cycle Off"; | 
 | 170 |             break; | 
 | 171 |         case PowerState::transitionToCycleOff: | 
 | 172 |             return "Transition to Power Cycle Off"; | 
 | 173 |             break; | 
 | 174 |         case PowerState::gracefulTransitionToCycleOff: | 
 | 175 |             return "Graceful Transition to Power Cycle Off"; | 
 | 176 |             break; | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 177 |         case PowerState::checkForWarmReset: | 
 | 178 |             return "Check for Warm Reset"; | 
 | 179 |             break; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 180 |         default: | 
 | 181 |             return "unknown state: " + std::to_string(static_cast<int>(state)); | 
 | 182 |             break; | 
 | 183 |     } | 
 | 184 | } | 
 | 185 | static void logStateTransition(const PowerState state) | 
 | 186 | { | 
| Vijay Khemka | d6c5ad1 | 2020-05-27 14:57:52 -0700 | [diff] [blame] | 187 |     std::string logMsg = | 
 | 188 |         "Host0: Moving to \"" + getPowerStateName(state) + "\" state"; | 
| Vijay Khemka | fc1ecc5 | 2020-04-01 10:49:28 -0700 | [diff] [blame] | 189 |     phosphor::logging::log<phosphor::logging::level::INFO>( | 
 | 190 |         logMsg.c_str(), | 
| Vijay Khemka | d6c5ad1 | 2020-05-27 14:57:52 -0700 | [diff] [blame] | 191 |         phosphor::logging::entry("STATE=%s", getPowerStateName(state).c_str()), | 
 | 192 |         phosphor::logging::entry("HOST=0")); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 193 | } | 
 | 194 |  | 
 | 195 | enum class Event | 
 | 196 | { | 
 | 197 |     psPowerOKAssert, | 
 | 198 |     psPowerOKDeAssert, | 
 | 199 |     sioPowerGoodAssert, | 
 | 200 |     sioPowerGoodDeAssert, | 
 | 201 |     sioS5Assert, | 
 | 202 |     sioS5DeAssert, | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 203 |     postCompleteAssert, | 
 | 204 |     postCompleteDeAssert, | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 205 |     powerButtonPressed, | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 206 |     resetButtonPressed, | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 207 |     powerCycleTimerExpired, | 
 | 208 |     psPowerOKWatchdogTimerExpired, | 
 | 209 |     sioPowerGoodWatchdogTimerExpired, | 
 | 210 |     gracefulPowerOffTimerExpired, | 
 | 211 |     powerOnRequest, | 
 | 212 |     powerOffRequest, | 
 | 213 |     powerCycleRequest, | 
 | 214 |     resetRequest, | 
 | 215 |     gracefulPowerOffRequest, | 
 | 216 |     gracefulPowerCycleRequest, | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 217 |     warmResetDetected, | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 218 | }; | 
 | 219 | static std::string getEventName(Event event) | 
 | 220 | { | 
 | 221 |     switch (event) | 
 | 222 |     { | 
 | 223 |         case Event::psPowerOKAssert: | 
 | 224 |             return "power supply power OK assert"; | 
 | 225 |             break; | 
 | 226 |         case Event::psPowerOKDeAssert: | 
 | 227 |             return "power supply power OK de-assert"; | 
 | 228 |             break; | 
 | 229 |         case Event::sioPowerGoodAssert: | 
 | 230 |             return "SIO power good assert"; | 
 | 231 |             break; | 
 | 232 |         case Event::sioPowerGoodDeAssert: | 
 | 233 |             return "SIO power good de-assert"; | 
 | 234 |             break; | 
 | 235 |         case Event::sioS5Assert: | 
 | 236 |             return "SIO S5 assert"; | 
 | 237 |             break; | 
 | 238 |         case Event::sioS5DeAssert: | 
 | 239 |             return "SIO S5 de-assert"; | 
 | 240 |             break; | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 241 |         case Event::postCompleteAssert: | 
 | 242 |             return "POST Complete assert"; | 
 | 243 |             break; | 
 | 244 |         case Event::postCompleteDeAssert: | 
 | 245 |             return "POST Complete de-assert"; | 
 | 246 |             break; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 247 |         case Event::powerButtonPressed: | 
 | 248 |             return "power button pressed"; | 
 | 249 |             break; | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 250 |         case Event::resetButtonPressed: | 
 | 251 |             return "reset button pressed"; | 
 | 252 |             break; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 253 |         case Event::powerCycleTimerExpired: | 
 | 254 |             return "power cycle timer expired"; | 
 | 255 |             break; | 
 | 256 |         case Event::psPowerOKWatchdogTimerExpired: | 
 | 257 |             return "power supply power OK watchdog timer expired"; | 
 | 258 |             break; | 
 | 259 |         case Event::sioPowerGoodWatchdogTimerExpired: | 
 | 260 |             return "SIO power good watchdog timer expired"; | 
 | 261 |             break; | 
 | 262 |         case Event::gracefulPowerOffTimerExpired: | 
 | 263 |             return "graceful power-off timer expired"; | 
 | 264 |             break; | 
 | 265 |         case Event::powerOnRequest: | 
 | 266 |             return "power-on request"; | 
 | 267 |             break; | 
 | 268 |         case Event::powerOffRequest: | 
 | 269 |             return "power-off request"; | 
 | 270 |             break; | 
 | 271 |         case Event::powerCycleRequest: | 
 | 272 |             return "power-cycle request"; | 
 | 273 |             break; | 
 | 274 |         case Event::resetRequest: | 
 | 275 |             return "reset request"; | 
 | 276 |             break; | 
 | 277 |         case Event::gracefulPowerOffRequest: | 
 | 278 |             return "graceful power-off request"; | 
 | 279 |             break; | 
 | 280 |         case Event::gracefulPowerCycleRequest: | 
 | 281 |             return "graceful power-cycle request"; | 
 | 282 |             break; | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 283 |         case Event::warmResetDetected: | 
 | 284 |             return "warm reset detected"; | 
 | 285 |             break; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 286 |         default: | 
 | 287 |             return "unknown event: " + std::to_string(static_cast<int>(event)); | 
 | 288 |             break; | 
 | 289 |     } | 
 | 290 | } | 
 | 291 | static void logEvent(const std::string_view stateHandler, const Event event) | 
 | 292 | { | 
| Vijay Khemka | fc1ecc5 | 2020-04-01 10:49:28 -0700 | [diff] [blame] | 293 |     std::string logMsg{stateHandler}; | 
 | 294 |     logMsg += ": " + getEventName(event) + " event received"; | 
 | 295 |     phosphor::logging::log<phosphor::logging::level::INFO>( | 
 | 296 |         logMsg.c_str(), | 
 | 297 |         phosphor::logging::entry("EVENT=%s", getEventName(event).c_str())); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 298 | } | 
 | 299 |  | 
 | 300 | // Power state handlers | 
 | 301 | static void powerStateOn(const Event event); | 
 | 302 | static void powerStateWaitForPSPowerOK(const Event event); | 
 | 303 | static void powerStateWaitForSIOPowerGood(const Event event); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 304 | static void powerStateOff(const Event event); | 
 | 305 | static void powerStateTransitionToOff(const Event event); | 
 | 306 | static void powerStateGracefulTransitionToOff(const Event event); | 
 | 307 | static void powerStateCycleOff(const Event event); | 
 | 308 | static void powerStateTransitionToCycleOff(const Event event); | 
 | 309 | static void powerStateGracefulTransitionToCycleOff(const Event event); | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 310 | static void powerStateCheckForWarmReset(const Event event); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 311 |  | 
 | 312 | static std::function<void(const Event)> getPowerStateHandler(PowerState state) | 
 | 313 | { | 
 | 314 |     switch (state) | 
 | 315 |     { | 
 | 316 |         case PowerState::on: | 
 | 317 |             return powerStateOn; | 
 | 318 |             break; | 
 | 319 |         case PowerState::waitForPSPowerOK: | 
 | 320 |             return powerStateWaitForPSPowerOK; | 
 | 321 |             break; | 
 | 322 |         case PowerState::waitForSIOPowerGood: | 
 | 323 |             return powerStateWaitForSIOPowerGood; | 
 | 324 |             break; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 325 |         case PowerState::off: | 
 | 326 |             return powerStateOff; | 
 | 327 |             break; | 
 | 328 |         case PowerState::transitionToOff: | 
 | 329 |             return powerStateTransitionToOff; | 
 | 330 |             break; | 
 | 331 |         case PowerState::gracefulTransitionToOff: | 
 | 332 |             return powerStateGracefulTransitionToOff; | 
 | 333 |             break; | 
 | 334 |         case PowerState::cycleOff: | 
 | 335 |             return powerStateCycleOff; | 
 | 336 |             break; | 
 | 337 |         case PowerState::transitionToCycleOff: | 
 | 338 |             return powerStateTransitionToCycleOff; | 
 | 339 |             break; | 
 | 340 |         case PowerState::gracefulTransitionToCycleOff: | 
 | 341 |             return powerStateGracefulTransitionToCycleOff; | 
 | 342 |             break; | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 343 |         case PowerState::checkForWarmReset: | 
 | 344 |             return powerStateCheckForWarmReset; | 
 | 345 |             break; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 346 |         default: | 
 | 347 |             return std::function<void(const Event)>{}; | 
 | 348 |             break; | 
 | 349 |     } | 
 | 350 | }; | 
 | 351 |  | 
 | 352 | static void sendPowerControlEvent(const Event event) | 
 | 353 | { | 
 | 354 |     std::function<void(const Event)> handler = getPowerStateHandler(powerState); | 
 | 355 |     if (handler == nullptr) | 
 | 356 |     { | 
 | 357 |         std::cerr << "Failed to find handler for power state: " | 
 | 358 |                   << static_cast<int>(powerState) << "\n"; | 
 | 359 |         return; | 
 | 360 |     } | 
 | 361 |     handler(event); | 
 | 362 | } | 
 | 363 |  | 
 | 364 | static uint64_t getCurrentTimeMs() | 
 | 365 | { | 
 | 366 |     struct timespec time = {}; | 
 | 367 |  | 
 | 368 |     if (clock_gettime(CLOCK_REALTIME, &time) < 0) | 
 | 369 |     { | 
 | 370 |         return 0; | 
 | 371 |     } | 
 | 372 |     uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000; | 
 | 373 |     currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000; | 
 | 374 |  | 
 | 375 |     return currentTimeMs; | 
 | 376 | } | 
 | 377 |  | 
 | 378 | static constexpr std::string_view getHostState(const PowerState state) | 
 | 379 | { | 
 | 380 |     switch (state) | 
 | 381 |     { | 
 | 382 |         case PowerState::on: | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 383 |         case PowerState::gracefulTransitionToOff: | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 384 |         case PowerState::gracefulTransitionToCycleOff: | 
 | 385 |             return "xyz.openbmc_project.State.Host.HostState.Running"; | 
 | 386 |             break; | 
 | 387 |         case PowerState::waitForPSPowerOK: | 
 | 388 |         case PowerState::waitForSIOPowerGood: | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 389 |         case PowerState::off: | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 390 |         case PowerState::transitionToOff: | 
 | 391 |         case PowerState::transitionToCycleOff: | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 392 |         case PowerState::cycleOff: | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 393 |         case PowerState::checkForWarmReset: | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 394 |             return "xyz.openbmc_project.State.Host.HostState.Off"; | 
 | 395 |             break; | 
 | 396 |         default: | 
 | 397 |             return ""; | 
 | 398 |             break; | 
 | 399 |     } | 
 | 400 | }; | 
 | 401 | static constexpr std::string_view getChassisState(const PowerState state) | 
 | 402 | { | 
 | 403 |     switch (state) | 
 | 404 |     { | 
 | 405 |         case PowerState::on: | 
 | 406 |         case PowerState::transitionToOff: | 
 | 407 |         case PowerState::gracefulTransitionToOff: | 
 | 408 |         case PowerState::transitionToCycleOff: | 
 | 409 |         case PowerState::gracefulTransitionToCycleOff: | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 410 |         case PowerState::checkForWarmReset: | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 411 |             return "xyz.openbmc_project.State.Chassis.PowerState.On"; | 
 | 412 |             break; | 
 | 413 |         case PowerState::waitForPSPowerOK: | 
 | 414 |         case PowerState::waitForSIOPowerGood: | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 415 |         case PowerState::off: | 
 | 416 |         case PowerState::cycleOff: | 
 | 417 |             return "xyz.openbmc_project.State.Chassis.PowerState.Off"; | 
 | 418 |             break; | 
 | 419 |         default: | 
 | 420 |             return ""; | 
 | 421 |             break; | 
 | 422 |     } | 
 | 423 | }; | 
 | 424 | static void savePowerState(const PowerState state) | 
 | 425 | { | 
 | 426 |     powerStateSaveTimer.expires_after( | 
 | 427 |         std::chrono::milliseconds(powerOffSaveTimeMs)); | 
 | 428 |     powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) { | 
 | 429 |         if (ec) | 
 | 430 |         { | 
 | 431 |             // operation_aborted is expected if timer is canceled before | 
 | 432 |             // completion. | 
 | 433 |             if (ec != boost::asio::error::operation_aborted) | 
 | 434 |             { | 
 | 435 |                 std::cerr << "Power-state save async_wait failed: " | 
 | 436 |                           << ec.message() << "\n"; | 
 | 437 |             } | 
 | 438 |             return; | 
 | 439 |         } | 
 | 440 |         std::ofstream powerStateStream(powerControlDir / powerStateFile); | 
 | 441 |         powerStateStream << getChassisState(state); | 
 | 442 |     }); | 
 | 443 | } | 
 | 444 | static void setPowerState(const PowerState state) | 
 | 445 | { | 
 | 446 |     powerState = state; | 
 | 447 |     logStateTransition(state); | 
 | 448 |  | 
 | 449 |     hostIface->set_property("CurrentHostState", | 
 | 450 |                             std::string(getHostState(powerState))); | 
 | 451 |  | 
 | 452 |     chassisIface->set_property("CurrentPowerState", | 
 | 453 |                                std::string(getChassisState(powerState))); | 
 | 454 |     chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs()); | 
 | 455 |  | 
 | 456 |     // Save the power state for the restore policy | 
 | 457 |     savePowerState(state); | 
 | 458 | } | 
 | 459 |  | 
 | 460 | enum class RestartCause | 
 | 461 | { | 
 | 462 |     command, | 
 | 463 |     resetButton, | 
 | 464 |     powerButton, | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 465 |     watchdog, | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 466 |     powerPolicyOn, | 
 | 467 |     powerPolicyRestore, | 
 | 468 |     softReset, | 
 | 469 | }; | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 470 | static boost::container::flat_set<RestartCause> causeSet; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 471 | static std::string getRestartCause(RestartCause cause) | 
 | 472 | { | 
 | 473 |     switch (cause) | 
 | 474 |     { | 
 | 475 |         case RestartCause::command: | 
 | 476 |             return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand"; | 
 | 477 |             break; | 
 | 478 |         case RestartCause::resetButton: | 
 | 479 |             return "xyz.openbmc_project.State.Host.RestartCause.ResetButton"; | 
 | 480 |             break; | 
 | 481 |         case RestartCause::powerButton: | 
 | 482 |             return "xyz.openbmc_project.State.Host.RestartCause.PowerButton"; | 
 | 483 |             break; | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 484 |         case RestartCause::watchdog: | 
 | 485 |             return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer"; | 
 | 486 |             break; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 487 |         case RestartCause::powerPolicyOn: | 
 | 488 |             return "xyz.openbmc_project.State.Host.RestartCause." | 
 | 489 |                    "PowerPolicyAlwaysOn"; | 
 | 490 |             break; | 
 | 491 |         case RestartCause::powerPolicyRestore: | 
 | 492 |             return "xyz.openbmc_project.State.Host.RestartCause." | 
 | 493 |                    "PowerPolicyPreviousState"; | 
 | 494 |             break; | 
 | 495 |         case RestartCause::softReset: | 
 | 496 |             return "xyz.openbmc_project.State.Host.RestartCause.SoftReset"; | 
 | 497 |             break; | 
 | 498 |         default: | 
 | 499 |             return "xyz.openbmc_project.State.Host.RestartCause.Unknown"; | 
 | 500 |             break; | 
 | 501 |     } | 
 | 502 | } | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 503 | static void addRestartCause(const RestartCause cause) | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 504 | { | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 505 |     // Add this to the set of causes for this restart | 
 | 506 |     causeSet.insert(cause); | 
 | 507 | } | 
 | 508 | static void clearRestartCause() | 
 | 509 | { | 
 | 510 |     // Clear the set for the next restart | 
 | 511 |     causeSet.clear(); | 
 | 512 | } | 
 | 513 | static void setRestartCauseProperty(const std::string& cause) | 
 | 514 | { | 
 | 515 |     std::cerr << "RestartCause set to " << cause << "\n"; | 
 | 516 |     restartCauseIface->set_property("RestartCause", cause); | 
 | 517 | } | 
| Rashmi RV | 89f6131 | 2020-01-22 15:41:50 +0530 | [diff] [blame] | 518 |  | 
 | 519 | static void resetACBootProperty() | 
 | 520 | { | 
 | 521 |     if ((causeSet.contains(RestartCause::command)) || | 
 | 522 |         (causeSet.contains(RestartCause::softReset))) | 
 | 523 |     { | 
 | 524 |         conn->async_method_call( | 
 | 525 |             [](boost::system::error_code ec) { | 
 | 526 |                 if (ec) | 
 | 527 |                 { | 
 | 528 |                     std::cerr << "failed to reset ACBoot property\n"; | 
 | 529 |                 } | 
 | 530 |             }, | 
 | 531 |             "xyz.openbmc_project.Settings", | 
 | 532 |             "/xyz/openbmc_project/control/host0/ac_boot", | 
 | 533 |             "org.freedesktop.DBus.Properties", "Set", | 
 | 534 |             "xyz.openbmc_project.Common.ACBoot", "ACBoot", | 
 | 535 |             std::variant<std::string>{"False"}); | 
 | 536 |     } | 
 | 537 | } | 
 | 538 |  | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 539 | static void setRestartCause() | 
 | 540 | { | 
 | 541 |     // Determine the actual restart cause based on the set of causes | 
 | 542 |     std::string restartCause = | 
 | 543 |         "xyz.openbmc_project.State.Host.RestartCause.Unknown"; | 
 | 544 |     if (causeSet.contains(RestartCause::watchdog)) | 
 | 545 |     { | 
 | 546 |         restartCause = getRestartCause(RestartCause::watchdog); | 
 | 547 |     } | 
 | 548 |     else if (causeSet.contains(RestartCause::command)) | 
 | 549 |     { | 
 | 550 |         restartCause = getRestartCause(RestartCause::command); | 
 | 551 |     } | 
 | 552 |     else if (causeSet.contains(RestartCause::resetButton)) | 
 | 553 |     { | 
 | 554 |         restartCause = getRestartCause(RestartCause::resetButton); | 
 | 555 |     } | 
 | 556 |     else if (causeSet.contains(RestartCause::powerButton)) | 
 | 557 |     { | 
 | 558 |         restartCause = getRestartCause(RestartCause::powerButton); | 
 | 559 |     } | 
 | 560 |     else if (causeSet.contains(RestartCause::powerPolicyOn)) | 
 | 561 |     { | 
 | 562 |         restartCause = getRestartCause(RestartCause::powerPolicyOn); | 
 | 563 |     } | 
 | 564 |     else if (causeSet.contains(RestartCause::powerPolicyRestore)) | 
 | 565 |     { | 
 | 566 |         restartCause = getRestartCause(RestartCause::powerPolicyRestore); | 
 | 567 |     } | 
 | 568 |     else if (causeSet.contains(RestartCause::softReset)) | 
 | 569 |     { | 
 | 570 |         restartCause = getRestartCause(RestartCause::softReset); | 
 | 571 |     } | 
 | 572 |  | 
 | 573 |     setRestartCauseProperty(restartCause); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 574 | } | 
 | 575 |  | 
| Jason M. Bills | 6c2ad36 | 2019-08-01 16:53:35 -0700 | [diff] [blame] | 576 | static void systemPowerGoodFailedLog() | 
 | 577 | { | 
 | 578 |     sd_journal_send( | 
 | 579 |         "MESSAGE=PowerControl: system power good failed to assert (VR failure)", | 
 | 580 |         "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s", | 
 | 581 |         "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d", | 
 | 582 |         sioPowerGoodWatchdogTimeMs, NULL); | 
 | 583 | } | 
 | 584 |  | 
 | 585 | static void psPowerOKFailedLog() | 
 | 586 | { | 
 | 587 |     sd_journal_send( | 
 | 588 |         "MESSAGE=PowerControl: power supply power good failed to assert", | 
 | 589 |         "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s", | 
 | 590 |         "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d", | 
 | 591 |         psPowerOKWatchdogTimeMs, NULL); | 
 | 592 | } | 
 | 593 |  | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 594 | static void powerRestorePolicyLog() | 
 | 595 | { | 
 | 596 |     sd_journal_send("MESSAGE=PowerControl: power restore policy applied", | 
 | 597 |                     "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s", | 
 | 598 |                     "OpenBMC.0.1.PowerRestorePolicyApplied", NULL); | 
 | 599 | } | 
 | 600 |  | 
 | 601 | static void powerButtonPressLog() | 
 | 602 | { | 
 | 603 |     sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i", | 
 | 604 |                     LOG_INFO, "REDFISH_MESSAGE_ID=%s", | 
 | 605 |                     "OpenBMC.0.1.PowerButtonPressed", NULL); | 
 | 606 | } | 
 | 607 |  | 
 | 608 | static void resetButtonPressLog() | 
 | 609 | { | 
 | 610 |     sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i", | 
 | 611 |                     LOG_INFO, "REDFISH_MESSAGE_ID=%s", | 
 | 612 |                     "OpenBMC.0.1.ResetButtonPressed", NULL); | 
 | 613 | } | 
 | 614 |  | 
 | 615 | static void nmiButtonPressLog() | 
 | 616 | { | 
 | 617 |     sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i", | 
 | 618 |                     LOG_INFO, "REDFISH_MESSAGE_ID=%s", | 
 | 619 |                     "OpenBMC.0.1.NMIButtonPressed", NULL); | 
 | 620 | } | 
 | 621 |  | 
 | 622 | static void nmiDiagIntLog() | 
 | 623 | { | 
 | 624 |     sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt", | 
 | 625 |                     "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s", | 
 | 626 |                     "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL); | 
 | 627 | } | 
 | 628 |  | 
 | 629 | static int initializePowerStateStorage() | 
 | 630 | { | 
 | 631 |     // create the power control directory if it doesn't exist | 
 | 632 |     std::error_code ec; | 
 | 633 |     if (!(std::filesystem::create_directories(powerControlDir, ec))) | 
 | 634 |     { | 
 | 635 |         if (ec.value() != 0) | 
 | 636 |         { | 
 | 637 |             std::cerr << "failed to create " << powerControlDir << ": " | 
 | 638 |                       << ec.message() << "\n"; | 
 | 639 |             return -1; | 
 | 640 |         } | 
 | 641 |     } | 
 | 642 |     // Create the power state file if it doesn't exist | 
 | 643 |     if (!std::filesystem::exists(powerControlDir / powerStateFile)) | 
 | 644 |     { | 
 | 645 |         std::ofstream powerStateStream(powerControlDir / powerStateFile); | 
 | 646 |         powerStateStream << getChassisState(powerState); | 
 | 647 |     } | 
 | 648 |     return 0; | 
 | 649 | } | 
 | 650 |  | 
 | 651 | static bool wasPowerDropped() | 
 | 652 | { | 
 | 653 |     std::ifstream powerStateStream(powerControlDir / powerStateFile); | 
 | 654 |     if (!powerStateStream.is_open()) | 
 | 655 |     { | 
 | 656 |         std::cerr << "Failed to open power state file\n"; | 
 | 657 |         return false; | 
 | 658 |     } | 
 | 659 |  | 
 | 660 |     std::string state; | 
 | 661 |     std::getline(powerStateStream, state); | 
 | 662 |     return state == "xyz.openbmc_project.State.Chassis.PowerState.On"; | 
 | 663 | } | 
 | 664 |  | 
 | 665 | static void invokePowerRestorePolicy(const std::string& policy) | 
 | 666 | { | 
 | 667 |     // Async events may call this twice, but we only want to run once | 
 | 668 |     static bool policyInvoked = false; | 
 | 669 |     if (policyInvoked) | 
 | 670 |     { | 
 | 671 |         return; | 
 | 672 |     } | 
 | 673 |     policyInvoked = true; | 
 | 674 |  | 
 | 675 |     std::cerr << "Power restore delay expired, invoking " << policy << "\n"; | 
 | 676 |     if (policy == | 
 | 677 |         "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn") | 
 | 678 |     { | 
 | 679 |         sendPowerControlEvent(Event::powerOnRequest); | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 680 |         setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn)); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 681 |     } | 
 | 682 |     else if (policy == "xyz.openbmc_project.Control.Power.RestorePolicy." | 
 | 683 |                        "Policy.Restore") | 
 | 684 |     { | 
 | 685 |         if (wasPowerDropped()) | 
 | 686 |         { | 
 | 687 |             std::cerr << "Power was dropped, restoring Host On state\n"; | 
 | 688 |             sendPowerControlEvent(Event::powerOnRequest); | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 689 |             setRestartCauseProperty( | 
 | 690 |                 getRestartCause(RestartCause::powerPolicyRestore)); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 691 |         } | 
 | 692 |         else | 
 | 693 |         { | 
 | 694 |             std::cerr << "No power drop, restoring Host Off state\n"; | 
 | 695 |         } | 
 | 696 |     } | 
| Jason M. Bills | 94ce8eb | 2019-09-30 10:13:25 -0700 | [diff] [blame] | 697 |     // We're done with the previous power state for the restore policy, so store | 
 | 698 |     // the current state | 
 | 699 |     savePowerState(powerState); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 700 | } | 
 | 701 |  | 
 | 702 | static void powerRestorePolicyDelay(int delay) | 
 | 703 | { | 
 | 704 |     // Async events may call this twice, but we only want to run once | 
 | 705 |     static bool delayStarted = false; | 
 | 706 |     if (delayStarted) | 
 | 707 |     { | 
 | 708 |         return; | 
 | 709 |     } | 
 | 710 |     delayStarted = true; | 
 | 711 |     // Calculate the delay from now to meet the requested delay | 
 | 712 |     // Subtract the approximate uboot time | 
 | 713 |     static constexpr const int ubootSeconds = 20; | 
 | 714 |     delay -= ubootSeconds; | 
 | 715 |     // Subtract the time since boot | 
 | 716 |     struct sysinfo info = {}; | 
 | 717 |     if (sysinfo(&info) == 0) | 
 | 718 |     { | 
 | 719 |         delay -= info.uptime; | 
 | 720 |     } | 
 | 721 |     // 0 is the minimum delay | 
 | 722 |     delay = std::max(delay, 0); | 
 | 723 |  | 
 | 724 |     static boost::asio::steady_timer powerRestorePolicyTimer(io); | 
 | 725 |     powerRestorePolicyTimer.expires_after(std::chrono::seconds(delay)); | 
 | 726 |     std::cerr << "Power restore delay of " << delay << " seconds started\n"; | 
 | 727 |     powerRestorePolicyTimer.async_wait([](const boost::system::error_code ec) { | 
 | 728 |         if (ec) | 
 | 729 |         { | 
 | 730 |             // operation_aborted is expected if timer is canceled before | 
 | 731 |             // completion. | 
 | 732 |             if (ec != boost::asio::error::operation_aborted) | 
 | 733 |             { | 
 | 734 |                 std::cerr << "power restore policy async_wait failed: " | 
 | 735 |                           << ec.message() << "\n"; | 
 | 736 |             } | 
 | 737 |             return; | 
 | 738 |         } | 
 | 739 |         // Get Power Restore Policy | 
 | 740 |         // In case PowerRestorePolicy is not available, set a match for it | 
 | 741 |         static std::unique_ptr<sdbusplus::bus::match::match> | 
 | 742 |             powerRestorePolicyMatch = std::make_unique< | 
 | 743 |                 sdbusplus::bus::match::match>( | 
 | 744 |                 *conn, | 
 | 745 |                 "type='signal',interface='org.freedesktop.DBus.Properties'," | 
 | 746 |                 "member='PropertiesChanged',arg0namespace='xyz.openbmc_" | 
 | 747 |                 "project.Control.Power.RestorePolicy'", | 
 | 748 |                 [](sdbusplus::message::message& msg) { | 
 | 749 |                     std::string interfaceName; | 
 | 750 |                     boost::container::flat_map<std::string, | 
 | 751 |                                                std::variant<std::string>> | 
 | 752 |                         propertiesChanged; | 
 | 753 |                     std::string policy; | 
 | 754 |                     try | 
 | 755 |                     { | 
 | 756 |                         msg.read(interfaceName, propertiesChanged); | 
 | 757 |                         policy = std::get<std::string>( | 
 | 758 |                             propertiesChanged.begin()->second); | 
 | 759 |                     } | 
 | 760 |                     catch (std::exception& e) | 
 | 761 |                     { | 
 | 762 |                         std::cerr | 
 | 763 |                             << "Unable to read power restore policy value\n"; | 
 | 764 |                         powerRestorePolicyMatch.reset(); | 
 | 765 |                         return; | 
 | 766 |                     } | 
 | 767 |                     invokePowerRestorePolicy(policy); | 
 | 768 |                     powerRestorePolicyMatch.reset(); | 
 | 769 |                 }); | 
 | 770 |  | 
 | 771 |         // Check if it's already on DBus | 
 | 772 |         conn->async_method_call( | 
 | 773 |             [](boost::system::error_code ec, | 
 | 774 |                const std::variant<std::string>& policyProperty) { | 
 | 775 |                 if (ec) | 
 | 776 |                 { | 
 | 777 |                     return; | 
 | 778 |                 } | 
 | 779 |                 powerRestorePolicyMatch.reset(); | 
 | 780 |                 const std::string* policy = | 
 | 781 |                     std::get_if<std::string>(&policyProperty); | 
 | 782 |                 if (policy == nullptr) | 
 | 783 |                 { | 
 | 784 |                     std::cerr << "Unable to read power restore policy value\n"; | 
 | 785 |                     return; | 
 | 786 |                 } | 
 | 787 |                 invokePowerRestorePolicy(*policy); | 
 | 788 |             }, | 
 | 789 |             "xyz.openbmc_project.Settings", | 
 | 790 |             "/xyz/openbmc_project/control/host0/power_restore_policy", | 
 | 791 |             "org.freedesktop.DBus.Properties", "Get", | 
 | 792 |             "xyz.openbmc_project.Control.Power.RestorePolicy", | 
 | 793 |             "PowerRestorePolicy"); | 
 | 794 |     }); | 
 | 795 | } | 
 | 796 |  | 
 | 797 | static void powerRestorePolicyStart() | 
 | 798 | { | 
 | 799 |     std::cerr << "Power restore policy started\n"; | 
 | 800 |     powerRestorePolicyLog(); | 
 | 801 |  | 
 | 802 |     // Get the desired delay time | 
 | 803 |     // In case PowerRestoreDelay is not available, set a match for it | 
 | 804 |     static std::unique_ptr<sdbusplus::bus::match::match> | 
 | 805 |         powerRestoreDelayMatch = std::make_unique<sdbusplus::bus::match::match>( | 
 | 806 |             *conn, | 
 | 807 |             "type='signal',interface='org.freedesktop.DBus.Properties',member='" | 
 | 808 |             "PropertiesChanged',arg0namespace='xyz.openbmc_project.Control." | 
 | 809 |             "Power.RestoreDelay'", | 
 | 810 |             [](sdbusplus::message::message& msg) { | 
 | 811 |                 std::string interfaceName; | 
 | 812 |                 boost::container::flat_map<std::string, std::variant<uint16_t>> | 
 | 813 |                     propertiesChanged; | 
 | 814 |                 int delay = 0; | 
 | 815 |                 try | 
 | 816 |                 { | 
 | 817 |                     msg.read(interfaceName, propertiesChanged); | 
 | 818 |                     delay = | 
 | 819 |                         std::get<uint16_t>(propertiesChanged.begin()->second); | 
 | 820 |                 } | 
 | 821 |                 catch (std::exception& e) | 
 | 822 |                 { | 
 | 823 |                     std::cerr << "Unable to read power restore delay value\n"; | 
 | 824 |                     powerRestoreDelayMatch.reset(); | 
 | 825 |                     return; | 
 | 826 |                 } | 
 | 827 |                 powerRestorePolicyDelay(delay); | 
 | 828 |                 powerRestoreDelayMatch.reset(); | 
 | 829 |             }); | 
 | 830 |  | 
 | 831 |     // Check if it's already on DBus | 
 | 832 |     conn->async_method_call( | 
 | 833 |         [](boost::system::error_code ec, | 
 | 834 |            const std::variant<uint16_t>& delayProperty) { | 
 | 835 |             if (ec) | 
 | 836 |             { | 
 | 837 |                 return; | 
 | 838 |             } | 
 | 839 |             powerRestoreDelayMatch.reset(); | 
 | 840 |             const uint16_t* delay = std::get_if<uint16_t>(&delayProperty); | 
 | 841 |             if (delay == nullptr) | 
 | 842 |             { | 
 | 843 |                 std::cerr << "Unable to read power restore delay value\n"; | 
 | 844 |                 return; | 
 | 845 |             } | 
 | 846 |             powerRestorePolicyDelay(*delay); | 
 | 847 |         }, | 
 | 848 |         "xyz.openbmc_project.Settings", | 
 | 849 |         "/xyz/openbmc_project/control/power_restore_delay", | 
 | 850 |         "org.freedesktop.DBus.Properties", "Get", | 
 | 851 |         "xyz.openbmc_project.Control.Power.RestoreDelay", "PowerRestoreDelay"); | 
 | 852 | } | 
 | 853 |  | 
 | 854 | static void powerRestorePolicyCheck() | 
 | 855 | { | 
 | 856 |     // In case ACBoot is not available, set a match for it | 
 | 857 |     static std::unique_ptr<sdbusplus::bus::match::match> acBootMatch = | 
 | 858 |         std::make_unique<sdbusplus::bus::match::match>( | 
 | 859 |             *conn, | 
 | 860 |             "type='signal',interface='org.freedesktop.DBus.Properties',member='" | 
 | 861 |             "PropertiesChanged',arg0namespace='xyz.openbmc_project.Common." | 
 | 862 |             "ACBoot'", | 
 | 863 |             [](sdbusplus::message::message& msg) { | 
 | 864 |                 std::string interfaceName; | 
 | 865 |                 boost::container::flat_map<std::string, | 
 | 866 |                                            std::variant<std::string>> | 
 | 867 |                     propertiesChanged; | 
 | 868 |                 std::string acBoot; | 
 | 869 |                 try | 
 | 870 |                 { | 
 | 871 |                     msg.read(interfaceName, propertiesChanged); | 
 | 872 |                     acBoot = std::get<std::string>( | 
 | 873 |                         propertiesChanged.begin()->second); | 
 | 874 |                 } | 
 | 875 |                 catch (std::exception& e) | 
 | 876 |                 { | 
 | 877 |                     std::cerr << "Unable to read AC Boot status\n"; | 
 | 878 |                     acBootMatch.reset(); | 
 | 879 |                     return; | 
 | 880 |                 } | 
 | 881 |                 if (acBoot == "Unknown") | 
 | 882 |                 { | 
 | 883 |                     return; | 
 | 884 |                 } | 
 | 885 |                 if (acBoot == "True") | 
 | 886 |                 { | 
 | 887 |                     // Start the Power Restore policy | 
 | 888 |                     powerRestorePolicyStart(); | 
 | 889 |                 } | 
 | 890 |                 acBootMatch.reset(); | 
 | 891 |             }); | 
 | 892 |  | 
 | 893 |     // Check if it's already on DBus | 
 | 894 |     conn->async_method_call( | 
 | 895 |         [](boost::system::error_code ec, | 
 | 896 |            const std::variant<std::string>& acBootProperty) { | 
 | 897 |             if (ec) | 
 | 898 |             { | 
 | 899 |                 return; | 
 | 900 |             } | 
 | 901 |             const std::string* acBoot = | 
 | 902 |                 std::get_if<std::string>(&acBootProperty); | 
 | 903 |             if (acBoot == nullptr) | 
 | 904 |             { | 
 | 905 |                 std::cerr << "Unable to read AC Boot status\n"; | 
 | 906 |                 return; | 
 | 907 |             } | 
 | 908 |             if (*acBoot == "Unknown") | 
 | 909 |             { | 
 | 910 |                 return; | 
 | 911 |             } | 
 | 912 |             if (*acBoot == "True") | 
 | 913 |             { | 
 | 914 |                 // Start the Power Restore policy | 
 | 915 |                 powerRestorePolicyStart(); | 
 | 916 |             } | 
 | 917 |             acBootMatch.reset(); | 
 | 918 |         }, | 
 | 919 |         "xyz.openbmc_project.Settings", | 
 | 920 |         "/xyz/openbmc_project/control/host0/ac_boot", | 
 | 921 |         "org.freedesktop.DBus.Properties", "Get", | 
 | 922 |         "xyz.openbmc_project.Common.ACBoot", "ACBoot"); | 
 | 923 | } | 
 | 924 |  | 
 | 925 | static bool requestGPIOEvents( | 
 | 926 |     const std::string& name, const std::function<void()>& handler, | 
 | 927 |     gpiod::line& gpioLine, | 
 | 928 |     boost::asio::posix::stream_descriptor& gpioEventDescriptor) | 
 | 929 | { | 
 | 930 |     // Find the GPIO line | 
 | 931 |     gpioLine = gpiod::find_line(name); | 
 | 932 |     if (!gpioLine) | 
 | 933 |     { | 
 | 934 |         std::cerr << "Failed to find the " << name << " line\n"; | 
 | 935 |         return false; | 
 | 936 |     } | 
 | 937 |  | 
 | 938 |     try | 
 | 939 |     { | 
 | 940 |         gpioLine.request( | 
 | 941 |             {"power-control", gpiod::line_request::EVENT_BOTH_EDGES}); | 
 | 942 |     } | 
 | 943 |     catch (std::exception&) | 
 | 944 |     { | 
 | 945 |         std::cerr << "Failed to request events for " << name << "\n"; | 
 | 946 |         return false; | 
 | 947 |     } | 
 | 948 |  | 
 | 949 |     int gpioLineFd = gpioLine.event_get_fd(); | 
 | 950 |     if (gpioLineFd < 0) | 
 | 951 |     { | 
 | 952 |         std::cerr << "Failed to get " << name << " fd\n"; | 
 | 953 |         return false; | 
 | 954 |     } | 
 | 955 |  | 
 | 956 |     gpioEventDescriptor.assign(gpioLineFd); | 
 | 957 |  | 
 | 958 |     gpioEventDescriptor.async_wait( | 
 | 959 |         boost::asio::posix::stream_descriptor::wait_read, | 
 | 960 |         [&name, handler](const boost::system::error_code ec) { | 
 | 961 |             if (ec) | 
 | 962 |             { | 
 | 963 |                 std::cerr << name << " fd handler error: " << ec.message() | 
 | 964 |                           << "\n"; | 
 | 965 |                 // TODO: throw here to force power-control to restart? | 
 | 966 |                 return; | 
 | 967 |             } | 
 | 968 |             handler(); | 
 | 969 |         }); | 
 | 970 |     return true; | 
 | 971 | } | 
 | 972 |  | 
 | 973 | static bool setGPIOOutput(const std::string& name, const int value, | 
 | 974 |                           gpiod::line& gpioLine) | 
 | 975 | { | 
 | 976 |     // Find the GPIO line | 
 | 977 |     gpioLine = gpiod::find_line(name); | 
 | 978 |     if (!gpioLine) | 
 | 979 |     { | 
 | 980 |         std::cerr << "Failed to find the " << name << " line.\n"; | 
 | 981 |         return false; | 
 | 982 |     } | 
 | 983 |  | 
 | 984 |     // Request GPIO output to specified value | 
 | 985 |     try | 
 | 986 |     { | 
 | 987 |         gpioLine.request({__FUNCTION__, gpiod::line_request::DIRECTION_OUTPUT}, | 
 | 988 |                          value); | 
 | 989 |     } | 
 | 990 |     catch (std::exception&) | 
 | 991 |     { | 
 | 992 |         std::cerr << "Failed to request " << name << " output\n"; | 
 | 993 |         return false; | 
 | 994 |     } | 
 | 995 |  | 
 | 996 |     std::cerr << name << " set to " << std::to_string(value) << "\n"; | 
 | 997 |     return true; | 
 | 998 | } | 
 | 999 |  | 
 | 1000 | static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine, | 
 | 1001 |                                     const std::string& name, const int value, | 
 | 1002 |                                     const int durationMs) | 
 | 1003 | { | 
 | 1004 |     // Set the masked GPIO line to the specified value | 
 | 1005 |     maskedGPIOLine.set_value(value); | 
 | 1006 |     std::cerr << name << " set to " << std::to_string(value) << "\n"; | 
 | 1007 |     gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs)); | 
 | 1008 |     gpioAssertTimer.async_wait( | 
 | 1009 |         [maskedGPIOLine, value, name](const boost::system::error_code ec) { | 
 | 1010 |             // Set the masked GPIO line back to the opposite value | 
 | 1011 |             maskedGPIOLine.set_value(!value); | 
 | 1012 |             std::cerr << name << " released\n"; | 
 | 1013 |             if (ec) | 
 | 1014 |             { | 
 | 1015 |                 // operation_aborted is expected if timer is canceled before | 
 | 1016 |                 // completion. | 
 | 1017 |                 if (ec != boost::asio::error::operation_aborted) | 
 | 1018 |                 { | 
 | 1019 |                     std::cerr << name << " async_wait failed: " + ec.message() | 
 | 1020 |                               << "\n"; | 
 | 1021 |                 } | 
 | 1022 |             } | 
 | 1023 |         }); | 
 | 1024 |     return 0; | 
 | 1025 | } | 
 | 1026 |  | 
 | 1027 | static int setGPIOOutputForMs(const std::string& name, const int value, | 
 | 1028 |                               const int durationMs) | 
 | 1029 | { | 
 | 1030 |     // If the requested GPIO is masked, use the mask line to set the output | 
| Vijay Khemka | 0dc7d4c | 2019-10-22 12:30:17 -0700 | [diff] [blame] | 1031 |     if (powerButtonMask && name == power_control::powerOutName) | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1032 |     { | 
 | 1033 |         return setMaskedGPIOOutputForMs(powerButtonMask, name, value, | 
 | 1034 |                                         durationMs); | 
 | 1035 |     } | 
| Vijay Khemka | 0dc7d4c | 2019-10-22 12:30:17 -0700 | [diff] [blame] | 1036 |     if (resetButtonMask && name == power_control::resetOutName) | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1037 |     { | 
 | 1038 |         return setMaskedGPIOOutputForMs(resetButtonMask, name, value, | 
 | 1039 |                                         durationMs); | 
 | 1040 |     } | 
 | 1041 |  | 
 | 1042 |     // No mask set, so request and set the GPIO normally | 
 | 1043 |     gpiod::line gpioLine; | 
 | 1044 |     if (!setGPIOOutput(name, value, gpioLine)) | 
 | 1045 |     { | 
 | 1046 |         return -1; | 
 | 1047 |     } | 
 | 1048 |     gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs)); | 
 | 1049 |     gpioAssertTimer.async_wait( | 
| Vijay Khemka | 0dc7d4c | 2019-10-22 12:30:17 -0700 | [diff] [blame] | 1050 |         [gpioLine, value, name](const boost::system::error_code ec) { | 
 | 1051 |             // Set the GPIO line back to the opposite value | 
 | 1052 |             gpioLine.set_value(!value); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1053 |             std::cerr << name << " released\n"; | 
 | 1054 |             if (ec) | 
 | 1055 |             { | 
 | 1056 |                 // operation_aborted is expected if timer is canceled before | 
 | 1057 |                 // completion. | 
 | 1058 |                 if (ec != boost::asio::error::operation_aborted) | 
 | 1059 |                 { | 
 | 1060 |                     std::cerr << name << " async_wait failed: " << ec.message() | 
 | 1061 |                               << "\n"; | 
 | 1062 |                 } | 
 | 1063 |             } | 
 | 1064 |         }); | 
 | 1065 |     return 0; | 
 | 1066 | } | 
 | 1067 |  | 
 | 1068 | static void powerOn() | 
 | 1069 | { | 
| Vijay Khemka | 0dc7d4c | 2019-10-22 12:30:17 -0700 | [diff] [blame] | 1070 |     setGPIOOutputForMs(power_control::powerOutName, 0, powerPulseTimeMs); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1071 | } | 
 | 1072 |  | 
 | 1073 | static void gracefulPowerOff() | 
 | 1074 | { | 
| Vijay Khemka | 0dc7d4c | 2019-10-22 12:30:17 -0700 | [diff] [blame] | 1075 |     setGPIOOutputForMs(power_control::powerOutName, 0, powerPulseTimeMs); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1076 | } | 
 | 1077 |  | 
 | 1078 | static void forcePowerOff() | 
 | 1079 | { | 
| Vijay Khemka | 0dc7d4c | 2019-10-22 12:30:17 -0700 | [diff] [blame] | 1080 |     if (setGPIOOutputForMs(power_control::powerOutName, 0, | 
 | 1081 |                            forceOffPulseTimeMs) < 0) | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1082 |     { | 
 | 1083 |         return; | 
 | 1084 |     } | 
 | 1085 |  | 
 | 1086 |     // If the force off timer expires, then the PCH power-button override | 
 | 1087 |     // failed, so attempt the Unconditional Powerdown SMBus command. | 
 | 1088 |     gpioAssertTimer.async_wait([](const boost::system::error_code ec) { | 
 | 1089 |         if (ec) | 
 | 1090 |         { | 
 | 1091 |             // operation_aborted is expected if timer is canceled before | 
 | 1092 |             // completion. | 
 | 1093 |             if (ec != boost::asio::error::operation_aborted) | 
 | 1094 |             { | 
 | 1095 |                 std::cerr << "Force power off async_wait failed: " | 
 | 1096 |                           << ec.message() << "\n"; | 
 | 1097 |             } | 
 | 1098 |             return; | 
 | 1099 |         } | 
 | 1100 |         std::cerr << "PCH Power-button override failed. Issuing Unconditional " | 
 | 1101 |                      "Powerdown SMBus command.\n"; | 
 | 1102 |         const static constexpr size_t pchDevBusAddress = 3; | 
 | 1103 |         const static constexpr size_t pchDevSlaveAddress = 0x44; | 
 | 1104 |         const static constexpr size_t pchCmdReg = 0; | 
 | 1105 |         const static constexpr size_t pchPowerDownCmd = 0x02; | 
 | 1106 |         if (i2cSet(pchDevBusAddress, pchDevSlaveAddress, pchCmdReg, | 
 | 1107 |                    pchPowerDownCmd) < 0) | 
 | 1108 |         { | 
 | 1109 |             std::cerr << "Unconditional Powerdown command failed! Not sure " | 
 | 1110 |                          "what to do now.\n"; | 
 | 1111 |         } | 
 | 1112 |     }); | 
 | 1113 | } | 
 | 1114 |  | 
 | 1115 | static void reset() | 
 | 1116 | { | 
| Vijay Khemka | 0dc7d4c | 2019-10-22 12:30:17 -0700 | [diff] [blame] | 1117 |     setGPIOOutputForMs(power_control::resetOutName, 0, resetPulseTimeMs); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1118 | } | 
 | 1119 |  | 
 | 1120 | static void gracefulPowerOffTimerStart() | 
 | 1121 | { | 
 | 1122 |     std::cerr << "Graceful power-off timer started\n"; | 
 | 1123 |     gracefulPowerOffTimer.expires_after( | 
 | 1124 |         std::chrono::milliseconds(gracefulPowerOffTimeMs)); | 
 | 1125 |     gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) { | 
 | 1126 |         if (ec) | 
 | 1127 |         { | 
 | 1128 |             // operation_aborted is expected if timer is canceled before | 
 | 1129 |             // completion. | 
 | 1130 |             if (ec != boost::asio::error::operation_aborted) | 
 | 1131 |             { | 
 | 1132 |                 std::cerr << "Graceful power-off async_wait failed: " | 
 | 1133 |                           << ec.message() << "\n"; | 
 | 1134 |             } | 
 | 1135 |             std::cerr << "Graceful power-off timer canceled\n"; | 
 | 1136 |             return; | 
 | 1137 |         } | 
 | 1138 |         std::cerr << "Graceful power-off timer completed\n"; | 
 | 1139 |         sendPowerControlEvent(Event::gracefulPowerOffTimerExpired); | 
 | 1140 |     }); | 
 | 1141 | } | 
 | 1142 |  | 
 | 1143 | static void powerCycleTimerStart() | 
 | 1144 | { | 
 | 1145 |     std::cerr << "Power-cycle timer started\n"; | 
 | 1146 |     powerCycleTimer.expires_after(std::chrono::milliseconds(powerCycleTimeMs)); | 
 | 1147 |     powerCycleTimer.async_wait([](const boost::system::error_code ec) { | 
 | 1148 |         if (ec) | 
 | 1149 |         { | 
 | 1150 |             // operation_aborted is expected if timer is canceled before | 
 | 1151 |             // completion. | 
 | 1152 |             if (ec != boost::asio::error::operation_aborted) | 
 | 1153 |             { | 
 | 1154 |                 std::cerr << "Power-cycle async_wait failed: " << ec.message() | 
 | 1155 |                           << "\n"; | 
 | 1156 |             } | 
 | 1157 |             std::cerr << "Power-cycle timer canceled\n"; | 
 | 1158 |             return; | 
 | 1159 |         } | 
 | 1160 |         std::cerr << "Power-cycle timer completed\n"; | 
 | 1161 |         sendPowerControlEvent(Event::powerCycleTimerExpired); | 
 | 1162 |     }); | 
 | 1163 | } | 
 | 1164 |  | 
 | 1165 | static void psPowerOKWatchdogTimerStart() | 
 | 1166 | { | 
 | 1167 |     std::cerr << "power supply power OK watchdog timer started\n"; | 
 | 1168 |     psPowerOKWatchdogTimer.expires_after( | 
 | 1169 |         std::chrono::milliseconds(psPowerOKWatchdogTimeMs)); | 
 | 1170 |     psPowerOKWatchdogTimer.async_wait( | 
 | 1171 |         [](const boost::system::error_code ec) { | 
 | 1172 |             if (ec) | 
 | 1173 |             { | 
 | 1174 |                 // operation_aborted is expected if timer is canceled before | 
 | 1175 |                 // completion. | 
 | 1176 |                 if (ec != boost::asio::error::operation_aborted) | 
 | 1177 |                 { | 
 | 1178 |                     std::cerr | 
 | 1179 |                         << "power supply power OK watchdog async_wait failed: " | 
 | 1180 |                         << ec.message() << "\n"; | 
 | 1181 |                 } | 
 | 1182 |                 std::cerr << "power supply power OK watchdog timer canceled\n"; | 
 | 1183 |                 return; | 
 | 1184 |             } | 
 | 1185 |             std::cerr << "power supply power OK watchdog timer expired\n"; | 
 | 1186 |             sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired); | 
 | 1187 |         }); | 
 | 1188 | } | 
 | 1189 |  | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 1190 | static void warmResetCheckTimerStart() | 
 | 1191 | { | 
 | 1192 |     std::cerr << "Warm reset check timer started\n"; | 
 | 1193 |     warmResetCheckTimer.expires_after( | 
 | 1194 |         std::chrono::milliseconds(warmResetCheckTimeMs)); | 
 | 1195 |     warmResetCheckTimer.async_wait([](const boost::system::error_code ec) { | 
 | 1196 |         if (ec) | 
 | 1197 |         { | 
 | 1198 |             // operation_aborted is expected if timer is canceled before | 
 | 1199 |             // completion. | 
 | 1200 |             if (ec != boost::asio::error::operation_aborted) | 
 | 1201 |             { | 
 | 1202 |                 std::cerr << "Warm reset check async_wait failed: " | 
 | 1203 |                           << ec.message() << "\n"; | 
 | 1204 |             } | 
 | 1205 |             std::cerr << "Warm reset check timer canceled\n"; | 
 | 1206 |             return; | 
 | 1207 |         } | 
 | 1208 |         std::cerr << "Warm reset check timer completed\n"; | 
 | 1209 |         sendPowerControlEvent(Event::warmResetDetected); | 
 | 1210 |     }); | 
 | 1211 | } | 
 | 1212 |  | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1213 | static void pohCounterTimerStart() | 
 | 1214 | { | 
 | 1215 |     std::cerr << "POH timer started\n"; | 
 | 1216 |     // Set the time-out as 1 hour, to align with POH command in ipmid | 
 | 1217 |     pohCounterTimer.expires_after(std::chrono::hours(1)); | 
 | 1218 |     pohCounterTimer.async_wait([](const boost::system::error_code& ec) { | 
 | 1219 |         if (ec) | 
 | 1220 |         { | 
 | 1221 |             // operation_aborted is expected if timer is canceled before | 
 | 1222 |             // completion. | 
 | 1223 |             if (ec != boost::asio::error::operation_aborted) | 
 | 1224 |             { | 
 | 1225 |                 std::cerr << "POH timer async_wait failed: " << ec.message() | 
 | 1226 |                           << "\n"; | 
 | 1227 |             } | 
 | 1228 |             std::cerr << "POH timer canceled\n"; | 
 | 1229 |             return; | 
 | 1230 |         } | 
 | 1231 |  | 
 | 1232 |         if (getHostState(powerState) != | 
 | 1233 |             "xyz.openbmc_project.State.Host.HostState.Running") | 
 | 1234 |         { | 
 | 1235 |             return; | 
 | 1236 |         } | 
 | 1237 |  | 
 | 1238 |         conn->async_method_call( | 
 | 1239 |             [](boost::system::error_code ec, | 
 | 1240 |                const std::variant<uint32_t>& pohCounterProperty) { | 
 | 1241 |                 if (ec) | 
 | 1242 |                 { | 
 | 1243 |                     std::cerr << "error to get poh counter\n"; | 
 | 1244 |                     return; | 
 | 1245 |                 } | 
 | 1246 |                 const uint32_t* pohCounter = | 
 | 1247 |                     std::get_if<uint32_t>(&pohCounterProperty); | 
 | 1248 |                 if (pohCounter == nullptr) | 
 | 1249 |                 { | 
 | 1250 |                     std::cerr << "unable to read poh counter\n"; | 
 | 1251 |                     return; | 
 | 1252 |                 } | 
 | 1253 |  | 
 | 1254 |                 conn->async_method_call( | 
 | 1255 |                     [](boost::system::error_code ec) { | 
 | 1256 |                         if (ec) | 
 | 1257 |                         { | 
 | 1258 |                             std::cerr << "failed to set poh counter\n"; | 
 | 1259 |                         } | 
 | 1260 |                     }, | 
 | 1261 |                     "xyz.openbmc_project.Settings", | 
 | 1262 |                     "/xyz/openbmc_project/state/chassis0", | 
 | 1263 |                     "org.freedesktop.DBus.Properties", "Set", | 
 | 1264 |                     "xyz.openbmc_project.State.PowerOnHours", "POHCounter", | 
 | 1265 |                     std::variant<uint32_t>(*pohCounter + 1)); | 
 | 1266 |             }, | 
 | 1267 |             "xyz.openbmc_project.Settings", | 
 | 1268 |             "/xyz/openbmc_project/state/chassis0", | 
 | 1269 |             "org.freedesktop.DBus.Properties", "Get", | 
 | 1270 |             "xyz.openbmc_project.State.PowerOnHours", "POHCounter"); | 
 | 1271 |  | 
 | 1272 |         pohCounterTimerStart(); | 
 | 1273 |     }); | 
 | 1274 | } | 
 | 1275 |  | 
 | 1276 | static void currentHostStateMonitor() | 
 | 1277 | { | 
| Yong Li | 8d66021 | 2019-12-27 10:18:10 +0800 | [diff] [blame] | 1278 |     if (getHostState(powerState) == | 
 | 1279 |         "xyz.openbmc_project.State.Host.HostState.Running") | 
 | 1280 |     { | 
 | 1281 |         pohCounterTimerStart(); | 
 | 1282 |         // Clear the restart cause set for the next restart | 
 | 1283 |         clearRestartCause(); | 
 | 1284 |     } | 
 | 1285 |     else | 
 | 1286 |     { | 
 | 1287 |         pohCounterTimer.cancel(); | 
 | 1288 |         // Set the restart cause set for this restart | 
 | 1289 |         setRestartCause(); | 
 | 1290 |     } | 
 | 1291 |  | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1292 |     static auto match = sdbusplus::bus::match::match( | 
 | 1293 |         *conn, | 
 | 1294 |         "type='signal',member='PropertiesChanged', " | 
 | 1295 |         "interface='org.freedesktop.DBus.Properties', " | 
 | 1296 |         "arg0namespace='xyz.openbmc_project.State.Host'", | 
 | 1297 |         [](sdbusplus::message::message& message) { | 
 | 1298 |             std::string intfName; | 
 | 1299 |             std::map<std::string, std::variant<std::string>> properties; | 
 | 1300 |  | 
 | 1301 |             message.read(intfName, properties); | 
 | 1302 |  | 
 | 1303 |             std::variant<std::string> currentHostState; | 
 | 1304 |  | 
 | 1305 |             try | 
 | 1306 |             { | 
 | 1307 |                 currentHostState = properties.at("CurrentHostState"); | 
 | 1308 |             } | 
 | 1309 |             catch (const std::out_of_range& e) | 
 | 1310 |             { | 
 | 1311 |                 std::cerr << "Error in finding CurrentHostState property\n"; | 
 | 1312 |  | 
 | 1313 |                 return; | 
 | 1314 |             } | 
 | 1315 |  | 
 | 1316 |             if (std::get<std::string>(currentHostState) == | 
 | 1317 |                 "xyz.openbmc_project.State.Host.HostState.Running") | 
 | 1318 |             { | 
 | 1319 |                 pohCounterTimerStart(); | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 1320 |                 // Clear the restart cause set for the next restart | 
 | 1321 |                 clearRestartCause(); | 
| Yong Li | 8d66021 | 2019-12-27 10:18:10 +0800 | [diff] [blame] | 1322 |                 sd_journal_send("MESSAGE=Host system DC power is on", | 
 | 1323 |                                 "PRIORITY=%i", LOG_INFO, | 
 | 1324 |                                 "REDFISH_MESSAGE_ID=%s", | 
 | 1325 |                                 "OpenBMC.0.1.DCPowerOn", NULL); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1326 |             } | 
 | 1327 |             else | 
 | 1328 |             { | 
 | 1329 |                 pohCounterTimer.cancel(); | 
| AppaRao Puli | 8f5cb6a | 2020-01-14 02:47:29 +0530 | [diff] [blame] | 1330 |                 // POST_COMPLETE GPIO event is not working in some platforms | 
 | 1331 |                 // when power state is changed to OFF. This resulted in | 
 | 1332 |                 // 'OperatingSystemState' to stay at 'Standby', even though | 
 | 1333 |                 // system is OFF. Set 'OperatingSystemState' to 'Inactive' | 
 | 1334 |                 // if HostState is trurned to OFF. | 
 | 1335 |                 osIface->set_property("OperatingSystemState", | 
 | 1336 |                                       std::string("Inactive")); | 
 | 1337 |  | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 1338 |                 // Set the restart cause set for this restart | 
 | 1339 |                 setRestartCause(); | 
| Rashmi RV | 89f6131 | 2020-01-22 15:41:50 +0530 | [diff] [blame] | 1340 |                 resetACBootProperty(); | 
| Yong Li | 8d66021 | 2019-12-27 10:18:10 +0800 | [diff] [blame] | 1341 |                 sd_journal_send("MESSAGE=Host system DC power is off", | 
 | 1342 |                                 "PRIORITY=%i", LOG_INFO, | 
 | 1343 |                                 "REDFISH_MESSAGE_ID=%s", | 
 | 1344 |                                 "OpenBMC.0.1.DCPowerOff", NULL); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1345 |             } | 
 | 1346 |         }); | 
 | 1347 | } | 
 | 1348 |  | 
 | 1349 | static void sioPowerGoodWatchdogTimerStart() | 
 | 1350 | { | 
 | 1351 |     std::cerr << "SIO power good watchdog timer started\n"; | 
 | 1352 |     sioPowerGoodWatchdogTimer.expires_after( | 
 | 1353 |         std::chrono::milliseconds(sioPowerGoodWatchdogTimeMs)); | 
 | 1354 |     sioPowerGoodWatchdogTimer.async_wait( | 
 | 1355 |         [](const boost::system::error_code ec) { | 
 | 1356 |             if (ec) | 
 | 1357 |             { | 
 | 1358 |                 // operation_aborted is expected if timer is canceled before | 
 | 1359 |                 // completion. | 
 | 1360 |                 if (ec != boost::asio::error::operation_aborted) | 
 | 1361 |                 { | 
 | 1362 |                     std::cerr << "SIO power good watchdog async_wait failed: " | 
 | 1363 |                               << ec.message() << "\n"; | 
 | 1364 |                 } | 
 | 1365 |                 std::cerr << "SIO power good watchdog timer canceled\n"; | 
 | 1366 |                 return; | 
 | 1367 |             } | 
 | 1368 |             std::cerr << "SIO power good watchdog timer completed\n"; | 
 | 1369 |             sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired); | 
 | 1370 |         }); | 
 | 1371 | } | 
 | 1372 |  | 
 | 1373 | static void powerStateOn(const Event event) | 
 | 1374 | { | 
 | 1375 |     logEvent(__FUNCTION__, event); | 
 | 1376 |     switch (event) | 
 | 1377 |     { | 
 | 1378 |         case Event::psPowerOKDeAssert: | 
 | 1379 |             setPowerState(PowerState::off); | 
 | 1380 |             // DC power is unexpectedly lost, beep | 
 | 1381 |             beep(beepPowerFail); | 
 | 1382 |             break; | 
 | 1383 |         case Event::sioS5Assert: | 
 | 1384 |             setPowerState(PowerState::transitionToOff); | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 1385 |             addRestartCause(RestartCause::softReset); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1386 |             break; | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 1387 |         case Event::postCompleteDeAssert: | 
 | 1388 |             setPowerState(PowerState::checkForWarmReset); | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 1389 |             addRestartCause(RestartCause::softReset); | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 1390 |             warmResetCheckTimerStart(); | 
 | 1391 |             break; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1392 |         case Event::powerButtonPressed: | 
 | 1393 |             setPowerState(PowerState::gracefulTransitionToOff); | 
 | 1394 |             gracefulPowerOffTimerStart(); | 
 | 1395 |             break; | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 1396 |         case Event::resetButtonPressed: | 
 | 1397 |             setPowerState(PowerState::checkForWarmReset); | 
 | 1398 |             warmResetCheckTimerStart(); | 
 | 1399 |             break; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1400 |         case Event::powerOffRequest: | 
 | 1401 |             setPowerState(PowerState::transitionToOff); | 
 | 1402 |             forcePowerOff(); | 
 | 1403 |             break; | 
 | 1404 |         case Event::gracefulPowerOffRequest: | 
 | 1405 |             setPowerState(PowerState::gracefulTransitionToOff); | 
 | 1406 |             gracefulPowerOffTimerStart(); | 
 | 1407 |             gracefulPowerOff(); | 
 | 1408 |             break; | 
 | 1409 |         case Event::powerCycleRequest: | 
 | 1410 |             setPowerState(PowerState::transitionToCycleOff); | 
 | 1411 |             forcePowerOff(); | 
 | 1412 |             break; | 
 | 1413 |         case Event::gracefulPowerCycleRequest: | 
 | 1414 |             setPowerState(PowerState::gracefulTransitionToCycleOff); | 
 | 1415 |             gracefulPowerOffTimerStart(); | 
 | 1416 |             gracefulPowerOff(); | 
 | 1417 |             break; | 
 | 1418 |         case Event::resetRequest: | 
 | 1419 |             reset(); | 
 | 1420 |             break; | 
 | 1421 |         default: | 
| Jason M. Bills | 95f631c | 2020-06-17 14:04:29 -0700 | [diff] [blame] | 1422 |             phosphor::logging::log<phosphor::logging::level::INFO>( | 
 | 1423 |                 "No action taken."); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1424 |             break; | 
 | 1425 |     } | 
 | 1426 | } | 
 | 1427 |  | 
 | 1428 | static void powerStateWaitForPSPowerOK(const Event event) | 
 | 1429 | { | 
 | 1430 |     logEvent(__FUNCTION__, event); | 
 | 1431 |     switch (event) | 
 | 1432 |     { | 
 | 1433 |         case Event::psPowerOKAssert: | 
 | 1434 |             // Cancel any GPIO assertions held during the transition | 
 | 1435 |             gpioAssertTimer.cancel(); | 
 | 1436 |             psPowerOKWatchdogTimer.cancel(); | 
 | 1437 |             sioPowerGoodWatchdogTimerStart(); | 
 | 1438 |             setPowerState(PowerState::waitForSIOPowerGood); | 
 | 1439 |             break; | 
 | 1440 |         case Event::psPowerOKWatchdogTimerExpired: | 
| Jason M. Bills | 273d789 | 2020-06-17 14:46:57 -0700 | [diff] [blame^] | 1441 |             setPowerState(PowerState::off); | 
| Jason M. Bills | 6c2ad36 | 2019-08-01 16:53:35 -0700 | [diff] [blame] | 1442 |             psPowerOKFailedLog(); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1443 |             break; | 
| Vijay Khemka | 0eef6b6 | 2019-10-22 12:22:52 -0700 | [diff] [blame] | 1444 |         case Event::sioPowerGoodAssert: | 
 | 1445 |             psPowerOKWatchdogTimer.cancel(); | 
 | 1446 |             setPowerState(PowerState::on); | 
 | 1447 |             break; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1448 |         default: | 
| Jason M. Bills | 95f631c | 2020-06-17 14:04:29 -0700 | [diff] [blame] | 1449 |             phosphor::logging::log<phosphor::logging::level::INFO>( | 
 | 1450 |                 "No action taken."); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1451 |             break; | 
 | 1452 |     } | 
 | 1453 | } | 
 | 1454 |  | 
 | 1455 | static void powerStateWaitForSIOPowerGood(const Event event) | 
 | 1456 | { | 
 | 1457 |     logEvent(__FUNCTION__, event); | 
 | 1458 |     switch (event) | 
 | 1459 |     { | 
 | 1460 |         case Event::sioPowerGoodAssert: | 
 | 1461 |             sioPowerGoodWatchdogTimer.cancel(); | 
 | 1462 |             setPowerState(PowerState::on); | 
 | 1463 |             break; | 
 | 1464 |         case Event::sioPowerGoodWatchdogTimerExpired: | 
| Jason M. Bills | 273d789 | 2020-06-17 14:46:57 -0700 | [diff] [blame^] | 1465 |             setPowerState(PowerState::off); | 
| Jason M. Bills | 6c2ad36 | 2019-08-01 16:53:35 -0700 | [diff] [blame] | 1466 |             systemPowerGoodFailedLog(); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1467 |             break; | 
 | 1468 |         default: | 
| Jason M. Bills | 95f631c | 2020-06-17 14:04:29 -0700 | [diff] [blame] | 1469 |             phosphor::logging::log<phosphor::logging::level::INFO>( | 
 | 1470 |                 "No action taken."); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1471 |             break; | 
 | 1472 |     } | 
 | 1473 | } | 
 | 1474 |  | 
 | 1475 | static void powerStateOff(const Event event) | 
 | 1476 | { | 
 | 1477 |     logEvent(__FUNCTION__, event); | 
 | 1478 |     switch (event) | 
 | 1479 |     { | 
 | 1480 |         case Event::psPowerOKAssert: | 
 | 1481 |             setPowerState(PowerState::waitForSIOPowerGood); | 
 | 1482 |             break; | 
 | 1483 |         case Event::sioS5DeAssert: | 
 | 1484 |             setPowerState(PowerState::waitForPSPowerOK); | 
 | 1485 |             break; | 
| Jason M. Bills | 273d789 | 2020-06-17 14:46:57 -0700 | [diff] [blame^] | 1486 |         case Event::sioPowerGoodAssert: | 
 | 1487 |             setPowerState(PowerState::on); | 
 | 1488 |             break; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1489 |         case Event::powerButtonPressed: | 
 | 1490 |             psPowerOKWatchdogTimerStart(); | 
 | 1491 |             setPowerState(PowerState::waitForPSPowerOK); | 
 | 1492 |             break; | 
 | 1493 |         case Event::powerOnRequest: | 
 | 1494 |             psPowerOKWatchdogTimerStart(); | 
 | 1495 |             setPowerState(PowerState::waitForPSPowerOK); | 
 | 1496 |             powerOn(); | 
 | 1497 |             break; | 
 | 1498 |         default: | 
| Jason M. Bills | 95f631c | 2020-06-17 14:04:29 -0700 | [diff] [blame] | 1499 |             phosphor::logging::log<phosphor::logging::level::INFO>( | 
 | 1500 |                 "No action taken."); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1501 |             break; | 
 | 1502 |     } | 
 | 1503 | } | 
 | 1504 |  | 
 | 1505 | static void powerStateTransitionToOff(const Event event) | 
 | 1506 | { | 
 | 1507 |     logEvent(__FUNCTION__, event); | 
 | 1508 |     switch (event) | 
 | 1509 |     { | 
 | 1510 |         case Event::psPowerOKDeAssert: | 
 | 1511 |             // Cancel any GPIO assertions held during the transition | 
 | 1512 |             gpioAssertTimer.cancel(); | 
 | 1513 |             setPowerState(PowerState::off); | 
 | 1514 |             break; | 
 | 1515 |         default: | 
| Jason M. Bills | 95f631c | 2020-06-17 14:04:29 -0700 | [diff] [blame] | 1516 |             phosphor::logging::log<phosphor::logging::level::INFO>( | 
 | 1517 |                 "No action taken."); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1518 |             break; | 
 | 1519 |     } | 
 | 1520 | } | 
 | 1521 |  | 
 | 1522 | static void powerStateGracefulTransitionToOff(const Event event) | 
 | 1523 | { | 
 | 1524 |     logEvent(__FUNCTION__, event); | 
 | 1525 |     switch (event) | 
 | 1526 |     { | 
 | 1527 |         case Event::psPowerOKDeAssert: | 
 | 1528 |             gracefulPowerOffTimer.cancel(); | 
 | 1529 |             setPowerState(PowerState::off); | 
 | 1530 |             break; | 
 | 1531 |         case Event::gracefulPowerOffTimerExpired: | 
 | 1532 |             setPowerState(PowerState::on); | 
 | 1533 |             break; | 
 | 1534 |         default: | 
| Jason M. Bills | 95f631c | 2020-06-17 14:04:29 -0700 | [diff] [blame] | 1535 |             phosphor::logging::log<phosphor::logging::level::INFO>( | 
 | 1536 |                 "No action taken."); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1537 |             break; | 
 | 1538 |     } | 
 | 1539 | } | 
 | 1540 |  | 
 | 1541 | static void powerStateCycleOff(const Event event) | 
 | 1542 | { | 
 | 1543 |     logEvent(__FUNCTION__, event); | 
 | 1544 |     switch (event) | 
 | 1545 |     { | 
| Jason M. Bills | 35aa665 | 2020-04-30 16:24:55 -0700 | [diff] [blame] | 1546 |         case Event::psPowerOKAssert: | 
 | 1547 |             powerCycleTimer.cancel(); | 
 | 1548 |             setPowerState(PowerState::waitForSIOPowerGood); | 
 | 1549 |             break; | 
 | 1550 |         case Event::sioS5DeAssert: | 
 | 1551 |             powerCycleTimer.cancel(); | 
 | 1552 |             setPowerState(PowerState::waitForPSPowerOK); | 
 | 1553 |             break; | 
 | 1554 |         case Event::powerButtonPressed: | 
 | 1555 |             powerCycleTimer.cancel(); | 
 | 1556 |             psPowerOKWatchdogTimerStart(); | 
 | 1557 |             setPowerState(PowerState::waitForPSPowerOK); | 
 | 1558 |             break; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1559 |         case Event::powerCycleTimerExpired: | 
 | 1560 |             psPowerOKWatchdogTimerStart(); | 
 | 1561 |             setPowerState(PowerState::waitForPSPowerOK); | 
 | 1562 |             powerOn(); | 
 | 1563 |             break; | 
 | 1564 |         default: | 
| Jason M. Bills | 95f631c | 2020-06-17 14:04:29 -0700 | [diff] [blame] | 1565 |             phosphor::logging::log<phosphor::logging::level::INFO>( | 
 | 1566 |                 "No action taken."); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1567 |             break; | 
 | 1568 |     } | 
 | 1569 | } | 
 | 1570 |  | 
 | 1571 | static void powerStateTransitionToCycleOff(const Event event) | 
 | 1572 | { | 
 | 1573 |     logEvent(__FUNCTION__, event); | 
 | 1574 |     switch (event) | 
 | 1575 |     { | 
 | 1576 |         case Event::psPowerOKDeAssert: | 
 | 1577 |             // Cancel any GPIO assertions held during the transition | 
 | 1578 |             gpioAssertTimer.cancel(); | 
 | 1579 |             setPowerState(PowerState::cycleOff); | 
 | 1580 |             powerCycleTimerStart(); | 
 | 1581 |             break; | 
 | 1582 |         default: | 
| Jason M. Bills | 95f631c | 2020-06-17 14:04:29 -0700 | [diff] [blame] | 1583 |             phosphor::logging::log<phosphor::logging::level::INFO>( | 
 | 1584 |                 "No action taken."); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1585 |             break; | 
 | 1586 |     } | 
 | 1587 | } | 
 | 1588 |  | 
 | 1589 | static void powerStateGracefulTransitionToCycleOff(const Event event) | 
 | 1590 | { | 
 | 1591 |     logEvent(__FUNCTION__, event); | 
 | 1592 |     switch (event) | 
 | 1593 |     { | 
 | 1594 |         case Event::psPowerOKDeAssert: | 
 | 1595 |             gracefulPowerOffTimer.cancel(); | 
 | 1596 |             setPowerState(PowerState::cycleOff); | 
 | 1597 |             powerCycleTimerStart(); | 
 | 1598 |             break; | 
 | 1599 |         case Event::gracefulPowerOffTimerExpired: | 
 | 1600 |             setPowerState(PowerState::on); | 
 | 1601 |             break; | 
 | 1602 |         default: | 
| Jason M. Bills | 95f631c | 2020-06-17 14:04:29 -0700 | [diff] [blame] | 1603 |             phosphor::logging::log<phosphor::logging::level::INFO>( | 
 | 1604 |                 "No action taken."); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1605 |             break; | 
 | 1606 |     } | 
 | 1607 | } | 
 | 1608 |  | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 1609 | static void powerStateCheckForWarmReset(const Event event) | 
 | 1610 | { | 
 | 1611 |     logEvent(__FUNCTION__, event); | 
 | 1612 |     switch (event) | 
 | 1613 |     { | 
 | 1614 |         case Event::sioS5Assert: | 
 | 1615 |             warmResetCheckTimer.cancel(); | 
 | 1616 |             setPowerState(PowerState::transitionToOff); | 
 | 1617 |             break; | 
 | 1618 |         case Event::warmResetDetected: | 
 | 1619 |             setPowerState(PowerState::on); | 
 | 1620 |             break; | 
| P.K. Lee | 344dae8 | 2019-11-27 16:35:05 +0800 | [diff] [blame] | 1621 |         case Event::psPowerOKDeAssert: | 
 | 1622 |             warmResetCheckTimer.cancel(); | 
 | 1623 |             setPowerState(PowerState::off); | 
 | 1624 |             // DC power is unexpectedly lost, beep | 
 | 1625 |             beep(beepPowerFail); | 
 | 1626 |             break; | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 1627 |         default: | 
| Jason M. Bills | 95f631c | 2020-06-17 14:04:29 -0700 | [diff] [blame] | 1628 |             phosphor::logging::log<phosphor::logging::level::INFO>( | 
 | 1629 |                 "No action taken."); | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 1630 |             break; | 
 | 1631 |     } | 
 | 1632 | } | 
 | 1633 |  | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1634 | static void psPowerOKHandler() | 
 | 1635 | { | 
 | 1636 |     gpiod::line_event gpioLineEvent = psPowerOKLine.event_read(); | 
 | 1637 |  | 
 | 1638 |     Event powerControlEvent = | 
 | 1639 |         gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE | 
 | 1640 |             ? Event::psPowerOKAssert | 
 | 1641 |             : Event::psPowerOKDeAssert; | 
 | 1642 |  | 
 | 1643 |     sendPowerControlEvent(powerControlEvent); | 
 | 1644 |     psPowerOKEvent.async_wait( | 
 | 1645 |         boost::asio::posix::stream_descriptor::wait_read, | 
 | 1646 |         [](const boost::system::error_code ec) { | 
 | 1647 |             if (ec) | 
 | 1648 |             { | 
 | 1649 |                 std::cerr << "power supply power OK handler error: " | 
 | 1650 |                           << ec.message() << "\n"; | 
 | 1651 |                 return; | 
 | 1652 |             } | 
 | 1653 |             psPowerOKHandler(); | 
 | 1654 |         }); | 
 | 1655 | } | 
 | 1656 |  | 
 | 1657 | static void sioPowerGoodHandler() | 
 | 1658 | { | 
 | 1659 |     gpiod::line_event gpioLineEvent = sioPowerGoodLine.event_read(); | 
 | 1660 |  | 
 | 1661 |     Event powerControlEvent = | 
 | 1662 |         gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE | 
 | 1663 |             ? Event::sioPowerGoodAssert | 
 | 1664 |             : Event::sioPowerGoodDeAssert; | 
 | 1665 |  | 
 | 1666 |     sendPowerControlEvent(powerControlEvent); | 
 | 1667 |     sioPowerGoodEvent.async_wait( | 
 | 1668 |         boost::asio::posix::stream_descriptor::wait_read, | 
 | 1669 |         [](const boost::system::error_code ec) { | 
 | 1670 |             if (ec) | 
 | 1671 |             { | 
 | 1672 |                 std::cerr << "SIO power good handler error: " << ec.message() | 
 | 1673 |                           << "\n"; | 
 | 1674 |                 return; | 
 | 1675 |             } | 
 | 1676 |             sioPowerGoodHandler(); | 
 | 1677 |         }); | 
 | 1678 | } | 
 | 1679 |  | 
 | 1680 | static void sioOnControlHandler() | 
 | 1681 | { | 
 | 1682 |     gpiod::line_event gpioLineEvent = sioOnControlLine.event_read(); | 
 | 1683 |  | 
 | 1684 |     bool sioOnControl = | 
 | 1685 |         gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE; | 
 | 1686 |     std::cerr << "SIO_ONCONTROL value changed: " << sioOnControl << "\n"; | 
 | 1687 |     sioOnControlEvent.async_wait( | 
 | 1688 |         boost::asio::posix::stream_descriptor::wait_read, | 
 | 1689 |         [](const boost::system::error_code ec) { | 
 | 1690 |             if (ec) | 
 | 1691 |             { | 
 | 1692 |                 std::cerr << "SIO ONCONTROL handler error: " << ec.message() | 
 | 1693 |                           << "\n"; | 
 | 1694 |                 return; | 
 | 1695 |             } | 
 | 1696 |             sioOnControlHandler(); | 
 | 1697 |         }); | 
 | 1698 | } | 
 | 1699 |  | 
 | 1700 | static void sioS5Handler() | 
 | 1701 | { | 
 | 1702 |     gpiod::line_event gpioLineEvent = sioS5Line.event_read(); | 
 | 1703 |  | 
 | 1704 |     Event powerControlEvent = | 
 | 1705 |         gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE | 
 | 1706 |             ? Event::sioS5Assert | 
 | 1707 |             : Event::sioS5DeAssert; | 
 | 1708 |  | 
 | 1709 |     sendPowerControlEvent(powerControlEvent); | 
 | 1710 |     sioS5Event.async_wait(boost::asio::posix::stream_descriptor::wait_read, | 
 | 1711 |                           [](const boost::system::error_code ec) { | 
 | 1712 |                               if (ec) | 
 | 1713 |                               { | 
 | 1714 |                                   std::cerr << "SIO S5 handler error: " | 
 | 1715 |                                             << ec.message() << "\n"; | 
 | 1716 |                                   return; | 
 | 1717 |                               } | 
 | 1718 |                               sioS5Handler(); | 
 | 1719 |                           }); | 
 | 1720 | } | 
 | 1721 |  | 
 | 1722 | static void powerButtonHandler() | 
 | 1723 | { | 
 | 1724 |     gpiod::line_event gpioLineEvent = powerButtonLine.event_read(); | 
 | 1725 |  | 
 | 1726 |     if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE) | 
 | 1727 |     { | 
 | 1728 |         powerButtonPressLog(); | 
 | 1729 |         powerButtonIface->set_property("ButtonPressed", true); | 
 | 1730 |         if (!powerButtonMask) | 
 | 1731 |         { | 
 | 1732 |             sendPowerControlEvent(Event::powerButtonPressed); | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 1733 |             addRestartCause(RestartCause::powerButton); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1734 |         } | 
 | 1735 |         else | 
 | 1736 |         { | 
 | 1737 |             std::cerr << "power button press masked\n"; | 
 | 1738 |         } | 
 | 1739 |     } | 
 | 1740 |     else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE) | 
 | 1741 |     { | 
 | 1742 |         powerButtonIface->set_property("ButtonPressed", false); | 
 | 1743 |     } | 
 | 1744 |     powerButtonEvent.async_wait( | 
 | 1745 |         boost::asio::posix::stream_descriptor::wait_read, | 
 | 1746 |         [](const boost::system::error_code ec) { | 
 | 1747 |             if (ec) | 
 | 1748 |             { | 
 | 1749 |                 std::cerr << "power button handler error: " << ec.message() | 
 | 1750 |                           << "\n"; | 
 | 1751 |                 return; | 
 | 1752 |             } | 
 | 1753 |             powerButtonHandler(); | 
 | 1754 |         }); | 
 | 1755 | } | 
 | 1756 |  | 
 | 1757 | static void resetButtonHandler() | 
 | 1758 | { | 
 | 1759 |     gpiod::line_event gpioLineEvent = resetButtonLine.event_read(); | 
 | 1760 |  | 
 | 1761 |     if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE) | 
 | 1762 |     { | 
 | 1763 |         resetButtonPressLog(); | 
 | 1764 |         resetButtonIface->set_property("ButtonPressed", true); | 
 | 1765 |         if (!resetButtonMask) | 
 | 1766 |         { | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 1767 |             sendPowerControlEvent(Event::resetButtonPressed); | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 1768 |             addRestartCause(RestartCause::resetButton); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1769 |         } | 
 | 1770 |         else | 
 | 1771 |         { | 
 | 1772 |             std::cerr << "reset button press masked\n"; | 
 | 1773 |         } | 
 | 1774 |     } | 
 | 1775 |     else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE) | 
 | 1776 |     { | 
 | 1777 |         resetButtonIface->set_property("ButtonPressed", false); | 
 | 1778 |     } | 
 | 1779 |     resetButtonEvent.async_wait( | 
 | 1780 |         boost::asio::posix::stream_descriptor::wait_read, | 
 | 1781 |         [](const boost::system::error_code ec) { | 
 | 1782 |             if (ec) | 
 | 1783 |             { | 
 | 1784 |                 std::cerr << "reset button handler error: " << ec.message() | 
 | 1785 |                           << "\n"; | 
 | 1786 |                 return; | 
 | 1787 |             } | 
 | 1788 |             resetButtonHandler(); | 
 | 1789 |         }); | 
 | 1790 | } | 
 | 1791 |  | 
| Vijay Khemka | 75ad0cf | 2020-04-02 15:23:51 -0700 | [diff] [blame] | 1792 | static constexpr auto systemdBusname = "org.freedesktop.systemd1"; | 
 | 1793 | static constexpr auto systemdPath = "/org/freedesktop/systemd1"; | 
 | 1794 | static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager"; | 
 | 1795 | static constexpr auto systemTargetName = "chassis-system-reset.target"; | 
 | 1796 |  | 
 | 1797 | void systemReset() | 
 | 1798 | { | 
 | 1799 |     conn->async_method_call( | 
 | 1800 |         [](boost::system::error_code ec) { | 
 | 1801 |             if (ec) | 
 | 1802 |             { | 
 | 1803 |                 phosphor::logging::log<phosphor::logging::level::ERR>( | 
 | 1804 |                     "Failed to call chassis system reset", | 
 | 1805 |                     phosphor::logging::entry("ERR=%s", ec.message().c_str())); | 
 | 1806 |             } | 
 | 1807 |         }, | 
 | 1808 |         systemdBusname, systemdPath, systemdInterface, "StartUnit", | 
 | 1809 |         systemTargetName, "replace"); | 
 | 1810 | } | 
 | 1811 |  | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1812 | static void nmiSetEnablePorperty(bool value) | 
 | 1813 | { | 
 | 1814 |     conn->async_method_call( | 
 | 1815 |         [](boost::system::error_code ec) { | 
 | 1816 |             if (ec) | 
 | 1817 |             { | 
 | 1818 |                 std::cerr << "failed to set NMI source\n"; | 
 | 1819 |             } | 
 | 1820 |         }, | 
| Chen Yugang | 303bd58 | 2019-11-01 08:45:06 +0800 | [diff] [blame] | 1821 |         "xyz.openbmc_project.Settings", | 
 | 1822 |         "/xyz/openbmc_project/Chassis/Control/NMISource", | 
 | 1823 |         "org.freedesktop.DBus.Properties", "Set", | 
 | 1824 |         "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled", | 
 | 1825 |         std::variant<bool>{value}); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1826 | } | 
 | 1827 |  | 
 | 1828 | static void nmiReset(void) | 
 | 1829 | { | 
 | 1830 |     static constexpr const uint8_t value = 1; | 
 | 1831 |     const static constexpr int nmiOutPulseTimeMs = 200; | 
 | 1832 |  | 
 | 1833 |     std::cerr << "NMI out action \n"; | 
 | 1834 |     nmiOutLine.set_value(value); | 
 | 1835 |     std::cerr << nmiOutName << " set to " << std::to_string(value) << "\n"; | 
 | 1836 |     gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs)); | 
 | 1837 |     gpioAssertTimer.async_wait([](const boost::system::error_code ec) { | 
 | 1838 |         // restore the NMI_OUT GPIO line back to the opposite value | 
 | 1839 |         nmiOutLine.set_value(!value); | 
 | 1840 |         std::cerr << nmiOutName << " released\n"; | 
 | 1841 |         if (ec) | 
 | 1842 |         { | 
 | 1843 |             // operation_aborted is expected if timer is canceled before | 
 | 1844 |             // completion. | 
 | 1845 |             if (ec != boost::asio::error::operation_aborted) | 
 | 1846 |             { | 
 | 1847 |                 std::cerr << nmiOutName << " async_wait failed: " + ec.message() | 
 | 1848 |                           << "\n"; | 
 | 1849 |             } | 
 | 1850 |         } | 
 | 1851 |     }); | 
 | 1852 |     // log to redfish | 
 | 1853 |     nmiDiagIntLog(); | 
 | 1854 |     std::cerr << "NMI out action completed\n"; | 
 | 1855 |     // reset Enable Property | 
 | 1856 |     nmiSetEnablePorperty(false); | 
 | 1857 | } | 
 | 1858 |  | 
 | 1859 | static void nmiSourcePropertyMonitor(void) | 
 | 1860 | { | 
 | 1861 |     std::cerr << " NMI Source Property Monitor \n"; | 
 | 1862 |  | 
 | 1863 |     static std::unique_ptr<sdbusplus::bus::match::match> nmiSourceMatch = | 
 | 1864 |         std::make_unique<sdbusplus::bus::match::match>( | 
 | 1865 |             *conn, | 
 | 1866 |             "type='signal',interface='org.freedesktop.DBus.Properties'," | 
| Chen Yugang | 303bd58 | 2019-11-01 08:45:06 +0800 | [diff] [blame] | 1867 |             "member='PropertiesChanged',arg0namespace='xyz.openbmc_project." | 
 | 1868 |             "Chassis.Control." | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1869 |             "NMISource'", | 
 | 1870 |             [](sdbusplus::message::message& msg) { | 
 | 1871 |                 std::string interfaceName; | 
 | 1872 |                 boost::container::flat_map<std::string, | 
 | 1873 |                                            std::variant<bool, std::string>> | 
 | 1874 |                     propertiesChanged; | 
 | 1875 |                 std::string state; | 
 | 1876 |                 bool value = true; | 
 | 1877 |                 try | 
 | 1878 |                 { | 
 | 1879 |                     msg.read(interfaceName, propertiesChanged); | 
 | 1880 |                     if (propertiesChanged.begin()->first == "Enabled") | 
 | 1881 |                     { | 
 | 1882 |                         value = | 
 | 1883 |                             std::get<bool>(propertiesChanged.begin()->second); | 
 | 1884 |                         std::cerr | 
 | 1885 |                             << " NMI Enabled propertiesChanged value: " << value | 
 | 1886 |                             << "\n"; | 
 | 1887 |                         nmiEnabled = value; | 
 | 1888 |                         if (nmiEnabled) | 
 | 1889 |                         { | 
 | 1890 |                             nmiReset(); | 
 | 1891 |                         } | 
 | 1892 |                     } | 
 | 1893 |                 } | 
 | 1894 |                 catch (std::exception& e) | 
 | 1895 |                 { | 
 | 1896 |                     std::cerr << "Unable to read NMI source\n"; | 
 | 1897 |                     return; | 
 | 1898 |                 } | 
 | 1899 |             }); | 
 | 1900 | } | 
 | 1901 |  | 
 | 1902 | static void setNmiSource() | 
 | 1903 | { | 
 | 1904 |     conn->async_method_call( | 
 | 1905 |         [](boost::system::error_code ec) { | 
 | 1906 |             if (ec) | 
 | 1907 |             { | 
 | 1908 |                 std::cerr << "failed to set NMI source\n"; | 
 | 1909 |             } | 
 | 1910 |         }, | 
| Chen Yugang | 303bd58 | 2019-11-01 08:45:06 +0800 | [diff] [blame] | 1911 |         "xyz.openbmc_project.Settings", | 
 | 1912 |         "/xyz/openbmc_project/Chassis/Control/NMISource", | 
 | 1913 |         "org.freedesktop.DBus.Properties", "Set", | 
 | 1914 |         "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource", | 
 | 1915 |         std::variant<std::string>{"xyz.openbmc_project.Chassis.Control." | 
 | 1916 |                                   "NMISource.BMCSourceSignal.FpBtn"}); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1917 |     // set Enable Property | 
 | 1918 |     nmiSetEnablePorperty(true); | 
 | 1919 | } | 
 | 1920 |  | 
 | 1921 | static void nmiButtonHandler() | 
 | 1922 | { | 
 | 1923 |     gpiod::line_event gpioLineEvent = nmiButtonLine.event_read(); | 
 | 1924 |  | 
 | 1925 |     if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE) | 
 | 1926 |     { | 
 | 1927 |         nmiButtonPressLog(); | 
 | 1928 |         nmiButtonIface->set_property("ButtonPressed", true); | 
 | 1929 |         if (nmiButtonMasked) | 
 | 1930 |         { | 
 | 1931 |             std::cerr << "NMI button press masked\n"; | 
 | 1932 |         } | 
 | 1933 |         else | 
 | 1934 |         { | 
 | 1935 |             setNmiSource(); | 
 | 1936 |         } | 
 | 1937 |     } | 
 | 1938 |     else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE) | 
 | 1939 |     { | 
 | 1940 |         nmiButtonIface->set_property("ButtonPressed", false); | 
 | 1941 |     } | 
 | 1942 |     nmiButtonEvent.async_wait(boost::asio::posix::stream_descriptor::wait_read, | 
 | 1943 |                               [](const boost::system::error_code ec) { | 
 | 1944 |                                   if (ec) | 
 | 1945 |                                   { | 
 | 1946 |                                       std::cerr << "NMI button handler error: " | 
 | 1947 |                                                 << ec.message() << "\n"; | 
 | 1948 |                                       return; | 
 | 1949 |                                   } | 
 | 1950 |                                   nmiButtonHandler(); | 
 | 1951 |                               }); | 
 | 1952 | } | 
 | 1953 |  | 
 | 1954 | static void idButtonHandler() | 
 | 1955 | { | 
 | 1956 |     gpiod::line_event gpioLineEvent = idButtonLine.event_read(); | 
 | 1957 |  | 
 | 1958 |     if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE) | 
 | 1959 |     { | 
 | 1960 |         idButtonIface->set_property("ButtonPressed", true); | 
 | 1961 |     } | 
 | 1962 |     else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE) | 
 | 1963 |     { | 
 | 1964 |         idButtonIface->set_property("ButtonPressed", false); | 
 | 1965 |     } | 
 | 1966 |     idButtonEvent.async_wait(boost::asio::posix::stream_descriptor::wait_read, | 
 | 1967 |                              [](const boost::system::error_code& ec) { | 
 | 1968 |                                  if (ec) | 
 | 1969 |                                  { | 
 | 1970 |                                      std::cerr << "ID button handler error: " | 
 | 1971 |                                                << ec.message() << "\n"; | 
 | 1972 |                                      return; | 
 | 1973 |                                  } | 
 | 1974 |                                  idButtonHandler(); | 
 | 1975 |                              }); | 
 | 1976 | } | 
 | 1977 |  | 
 | 1978 | static void postCompleteHandler() | 
 | 1979 | { | 
 | 1980 |     gpiod::line_event gpioLineEvent = postCompleteLine.event_read(); | 
 | 1981 |  | 
 | 1982 |     bool postComplete = | 
 | 1983 |         gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1984 |     if (postComplete) | 
 | 1985 |     { | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 1986 |         sendPowerControlEvent(Event::postCompleteAssert); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1987 |         osIface->set_property("OperatingSystemState", std::string("Standby")); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1988 |     } | 
 | 1989 |     else | 
 | 1990 |     { | 
| Jason M. Bills | e9a9e2d | 2019-08-08 14:01:19 -0700 | [diff] [blame] | 1991 |         sendPowerControlEvent(Event::postCompleteDeAssert); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1992 |         osIface->set_property("OperatingSystemState", std::string("Inactive")); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 1993 |     } | 
 | 1994 |     postCompleteEvent.async_wait( | 
 | 1995 |         boost::asio::posix::stream_descriptor::wait_read, | 
 | 1996 |         [](const boost::system::error_code ec) { | 
 | 1997 |             if (ec) | 
 | 1998 |             { | 
 | 1999 |                 std::cerr << "POST complete handler error: " << ec.message() | 
 | 2000 |                           << "\n"; | 
 | 2001 |                 return; | 
 | 2002 |             } | 
 | 2003 |             postCompleteHandler(); | 
 | 2004 |         }); | 
 | 2005 | } | 
 | 2006 | } // namespace power_control | 
 | 2007 |  | 
 | 2008 | int main(int argc, char* argv[]) | 
 | 2009 | { | 
 | 2010 |     std::cerr << "Start Chassis power control service...\n"; | 
 | 2011 |     power_control::conn = | 
 | 2012 |         std::make_shared<sdbusplus::asio::connection>(power_control::io); | 
 | 2013 |  | 
 | 2014 |     // Request all the dbus names | 
 | 2015 |     power_control::conn->request_name("xyz.openbmc_project.State.Host"); | 
 | 2016 |     power_control::conn->request_name("xyz.openbmc_project.State.Chassis"); | 
 | 2017 |     power_control::conn->request_name( | 
 | 2018 |         "xyz.openbmc_project.State.OperatingSystem"); | 
 | 2019 |     power_control::conn->request_name("xyz.openbmc_project.Chassis.Buttons"); | 
| Chen Yugang | 174ec66 | 2019-08-19 19:58:49 +0800 | [diff] [blame] | 2020 |     power_control::conn->request_name("xyz.openbmc_project.Control.Host.NMI"); | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 2021 |     power_control::conn->request_name( | 
 | 2022 |         "xyz.openbmc_project.Control.Host.RestartCause"); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2023 |  | 
 | 2024 |     // Request PS_PWROK GPIO events | 
 | 2025 |     if (!power_control::requestGPIOEvents( | 
 | 2026 |             "PS_PWROK", power_control::psPowerOKHandler, | 
 | 2027 |             power_control::psPowerOKLine, power_control::psPowerOKEvent)) | 
 | 2028 |     { | 
 | 2029 |         return -1; | 
 | 2030 |     } | 
 | 2031 |  | 
 | 2032 |     // Request SIO_POWER_GOOD GPIO events | 
 | 2033 |     if (!power_control::requestGPIOEvents( | 
 | 2034 |             "SIO_POWER_GOOD", power_control::sioPowerGoodHandler, | 
 | 2035 |             power_control::sioPowerGoodLine, power_control::sioPowerGoodEvent)) | 
 | 2036 |     { | 
 | 2037 |         return -1; | 
 | 2038 |     } | 
 | 2039 |  | 
 | 2040 |     // Request SIO_ONCONTROL GPIO events | 
 | 2041 |     if (!power_control::requestGPIOEvents( | 
 | 2042 |             "SIO_ONCONTROL", power_control::sioOnControlHandler, | 
 | 2043 |             power_control::sioOnControlLine, power_control::sioOnControlEvent)) | 
 | 2044 |     { | 
 | 2045 |         return -1; | 
 | 2046 |     } | 
 | 2047 |  | 
 | 2048 |     // Request SIO_S5 GPIO events | 
 | 2049 |     if (!power_control::requestGPIOEvents("SIO_S5", power_control::sioS5Handler, | 
 | 2050 |                                           power_control::sioS5Line, | 
 | 2051 |                                           power_control::sioS5Event)) | 
 | 2052 |     { | 
 | 2053 |         return -1; | 
 | 2054 |     } | 
 | 2055 |  | 
 | 2056 |     // Request POWER_BUTTON GPIO events | 
 | 2057 |     if (!power_control::requestGPIOEvents( | 
 | 2058 |             "POWER_BUTTON", power_control::powerButtonHandler, | 
 | 2059 |             power_control::powerButtonLine, power_control::powerButtonEvent)) | 
 | 2060 |     { | 
 | 2061 |         return -1; | 
 | 2062 |     } | 
 | 2063 |  | 
 | 2064 |     // Request RESET_BUTTON GPIO events | 
 | 2065 |     if (!power_control::requestGPIOEvents( | 
 | 2066 |             "RESET_BUTTON", power_control::resetButtonHandler, | 
 | 2067 |             power_control::resetButtonLine, power_control::resetButtonEvent)) | 
 | 2068 |     { | 
 | 2069 |         return -1; | 
 | 2070 |     } | 
 | 2071 |  | 
 | 2072 |     // Request NMI_BUTTON GPIO events | 
| Vijay Khemka | 33a532d | 2019-11-14 16:50:35 -0800 | [diff] [blame] | 2073 |     power_control::requestGPIOEvents( | 
 | 2074 |         "NMI_BUTTON", power_control::nmiButtonHandler, | 
 | 2075 |         power_control::nmiButtonLine, power_control::nmiButtonEvent); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2076 |  | 
 | 2077 |     // Request ID_BUTTON GPIO events | 
| Vijay Khemka | 33a532d | 2019-11-14 16:50:35 -0800 | [diff] [blame] | 2078 |     power_control::requestGPIOEvents( | 
 | 2079 |         "ID_BUTTON", power_control::idButtonHandler, | 
 | 2080 |         power_control::idButtonLine, power_control::idButtonEvent); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2081 |  | 
 | 2082 |     // Request POST_COMPLETE GPIO events | 
 | 2083 |     if (!power_control::requestGPIOEvents( | 
 | 2084 |             "POST_COMPLETE", power_control::postCompleteHandler, | 
 | 2085 |             power_control::postCompleteLine, power_control::postCompleteEvent)) | 
 | 2086 |     { | 
 | 2087 |         return -1; | 
 | 2088 |     } | 
 | 2089 |  | 
 | 2090 |     // initialize NMI_OUT GPIO. | 
| Vijay Khemka | 33a532d | 2019-11-14 16:50:35 -0800 | [diff] [blame] | 2091 |     power_control::setGPIOOutput(power_control::nmiOutName, 0, | 
 | 2092 |                                  power_control::nmiOutLine); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2093 |  | 
| Vijay Khemka | 0dc7d4c | 2019-10-22 12:30:17 -0700 | [diff] [blame] | 2094 |     // Initialize POWER_OUT and RESET_OUT GPIO. | 
 | 2095 |     gpiod::line line; | 
 | 2096 |     if (!power_control::setGPIOOutput(power_control::powerOutName, 1, line)) | 
 | 2097 |     { | 
 | 2098 |         return -1; | 
 | 2099 |     } | 
 | 2100 |  | 
 | 2101 |     if (!power_control::setGPIOOutput(power_control::resetOutName, 1, line)) | 
 | 2102 |     { | 
 | 2103 |         return -1; | 
 | 2104 |     } | 
 | 2105 |  | 
 | 2106 |     // Release line | 
 | 2107 |     line.reset(); | 
 | 2108 |  | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2109 |     // Initialize the power state | 
 | 2110 |     power_control::powerState = power_control::PowerState::off; | 
 | 2111 |     // Check power good | 
 | 2112 |     if (power_control::psPowerOKLine.get_value() > 0) | 
 | 2113 |     { | 
 | 2114 |         power_control::powerState = power_control::PowerState::on; | 
 | 2115 |     } | 
 | 2116 |  | 
 | 2117 |     // Initialize the power state storage | 
 | 2118 |     if (power_control::initializePowerStateStorage() < 0) | 
 | 2119 |     { | 
 | 2120 |         return -1; | 
 | 2121 |     } | 
 | 2122 |  | 
 | 2123 |     // Check if we need to start the Power Restore policy | 
 | 2124 |     power_control::powerRestorePolicyCheck(); | 
 | 2125 |  | 
| Vijay Khemka | 33a532d | 2019-11-14 16:50:35 -0800 | [diff] [blame] | 2126 |     if (power_control::nmiOutLine) | 
 | 2127 |         power_control::nmiSourcePropertyMonitor(); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2128 |  | 
 | 2129 |     std::cerr << "Initializing power state. "; | 
 | 2130 |     power_control::logStateTransition(power_control::powerState); | 
 | 2131 |  | 
 | 2132 |     // Power Control Service | 
 | 2133 |     sdbusplus::asio::object_server hostServer = | 
 | 2134 |         sdbusplus::asio::object_server(power_control::conn); | 
 | 2135 |  | 
 | 2136 |     // Power Control Interface | 
 | 2137 |     power_control::hostIface = hostServer.add_interface( | 
 | 2138 |         "/xyz/openbmc_project/state/host0", "xyz.openbmc_project.State.Host"); | 
 | 2139 |  | 
 | 2140 |     power_control::hostIface->register_property( | 
 | 2141 |         "RequestedHostTransition", | 
 | 2142 |         std::string("xyz.openbmc_project.State.Host.Transition.Off"), | 
 | 2143 |         [](const std::string& requested, std::string& resp) { | 
 | 2144 |             if (requested == "xyz.openbmc_project.State.Host.Transition.Off") | 
 | 2145 |             { | 
 | 2146 |                 sendPowerControlEvent( | 
 | 2147 |                     power_control::Event::gracefulPowerOffRequest); | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 2148 |                 addRestartCause(power_control::RestartCause::command); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2149 |             } | 
 | 2150 |             else if (requested == | 
 | 2151 |                      "xyz.openbmc_project.State.Host.Transition.On") | 
 | 2152 |             { | 
 | 2153 |                 sendPowerControlEvent(power_control::Event::powerOnRequest); | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 2154 |                 addRestartCause(power_control::RestartCause::command); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2155 |             } | 
 | 2156 |             else if (requested == | 
 | 2157 |                      "xyz.openbmc_project.State.Host.Transition.Reboot") | 
 | 2158 |             { | 
| Jason M. Bills | e7520ba | 2020-01-31 11:19:03 -0800 | [diff] [blame] | 2159 |                 sendPowerControlEvent(power_control::Event::powerCycleRequest); | 
 | 2160 |                 addRestartCause(power_control::RestartCause::command); | 
 | 2161 |             } | 
 | 2162 |             else if (requested == "xyz.openbmc_project.State.Host.Transition." | 
 | 2163 |                                   "GracefulWarmReboot") | 
 | 2164 |             { | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2165 |                 sendPowerControlEvent( | 
 | 2166 |                     power_control::Event::gracefulPowerCycleRequest); | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 2167 |                 addRestartCause(power_control::RestartCause::command); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2168 |             } | 
| Jason M. Bills | e7520ba | 2020-01-31 11:19:03 -0800 | [diff] [blame] | 2169 |             else if (requested == "xyz.openbmc_project.State.Host.Transition." | 
 | 2170 |                                   "ForceWarmReboot") | 
 | 2171 |             { | 
 | 2172 |                 sendPowerControlEvent(power_control::Event::resetRequest); | 
 | 2173 |                 addRestartCause(power_control::RestartCause::command); | 
 | 2174 |             } | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2175 |             else | 
 | 2176 |             { | 
 | 2177 |                 std::cerr << "Unrecognized host state transition request.\n"; | 
 | 2178 |                 throw std::invalid_argument("Unrecognized Transition Request"); | 
 | 2179 |                 return 0; | 
 | 2180 |             } | 
 | 2181 |             resp = requested; | 
 | 2182 |             return 1; | 
 | 2183 |         }); | 
 | 2184 |     power_control::hostIface->register_property( | 
 | 2185 |         "CurrentHostState", | 
 | 2186 |         std::string(power_control::getHostState(power_control::powerState))); | 
 | 2187 |  | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2188 |     power_control::hostIface->initialize(); | 
 | 2189 |  | 
 | 2190 |     // Chassis Control Service | 
 | 2191 |     sdbusplus::asio::object_server chassisServer = | 
 | 2192 |         sdbusplus::asio::object_server(power_control::conn); | 
 | 2193 |  | 
 | 2194 |     // Chassis Control Interface | 
 | 2195 |     power_control::chassisIface = | 
 | 2196 |         chassisServer.add_interface("/xyz/openbmc_project/state/chassis0", | 
 | 2197 |                                     "xyz.openbmc_project.State.Chassis"); | 
 | 2198 |  | 
 | 2199 |     power_control::chassisIface->register_property( | 
 | 2200 |         "RequestedPowerTransition", | 
 | 2201 |         std::string("xyz.openbmc_project.State.Chassis.Transition.Off"), | 
 | 2202 |         [](const std::string& requested, std::string& resp) { | 
 | 2203 |             if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off") | 
 | 2204 |             { | 
 | 2205 |                 sendPowerControlEvent(power_control::Event::powerOffRequest); | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 2206 |                 addRestartCause(power_control::RestartCause::command); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2207 |             } | 
 | 2208 |             else if (requested == | 
 | 2209 |                      "xyz.openbmc_project.State.Chassis.Transition.On") | 
 | 2210 |             { | 
 | 2211 |                 sendPowerControlEvent(power_control::Event::powerOnRequest); | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 2212 |                 addRestartCause(power_control::RestartCause::command); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2213 |             } | 
 | 2214 |             else if (requested == | 
 | 2215 |                      "xyz.openbmc_project.State.Chassis.Transition.PowerCycle") | 
 | 2216 |             { | 
 | 2217 |                 sendPowerControlEvent(power_control::Event::powerCycleRequest); | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 2218 |                 addRestartCause(power_control::RestartCause::command); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2219 |             } | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2220 |             else | 
 | 2221 |             { | 
 | 2222 |                 std::cerr << "Unrecognized chassis state transition request.\n"; | 
 | 2223 |                 throw std::invalid_argument("Unrecognized Transition Request"); | 
 | 2224 |                 return 0; | 
 | 2225 |             } | 
 | 2226 |             resp = requested; | 
 | 2227 |             return 1; | 
 | 2228 |         }); | 
 | 2229 |     power_control::chassisIface->register_property( | 
 | 2230 |         "CurrentPowerState", | 
 | 2231 |         std::string(power_control::getChassisState(power_control::powerState))); | 
 | 2232 |     power_control::chassisIface->register_property( | 
 | 2233 |         "LastStateChangeTime", power_control::getCurrentTimeMs()); | 
 | 2234 |  | 
 | 2235 |     power_control::chassisIface->initialize(); | 
 | 2236 |  | 
| Vijay Khemka | 75ad0cf | 2020-04-02 15:23:51 -0700 | [diff] [blame] | 2237 |     // Chassis System Service | 
 | 2238 |     sdbusplus::asio::object_server chassisSysServer = | 
 | 2239 |         sdbusplus::asio::object_server(power_control::conn); | 
 | 2240 |  | 
 | 2241 |     // Chassis System Interface | 
 | 2242 |     power_control::chassisSysIface = chassisSysServer.add_interface( | 
 | 2243 |         "/xyz/openbmc_project/state/chassis_system0", | 
 | 2244 |         "xyz.openbmc_project.State.Chassis"); | 
 | 2245 |  | 
 | 2246 |     power_control::chassisSysIface->register_property( | 
 | 2247 |         "RequestedPowerTransition", | 
 | 2248 |         std::string("xyz.openbmc_project.State.Chassis.Transition.On"), | 
 | 2249 |         [](const std::string& requested, std::string& resp) { | 
 | 2250 |             if (requested == | 
 | 2251 |                 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle") | 
 | 2252 |             { | 
 | 2253 |                 power_control::systemReset(); | 
 | 2254 |                 addRestartCause(power_control::RestartCause::command); | 
 | 2255 |             } | 
 | 2256 |             else | 
 | 2257 |             { | 
 | 2258 |                 std::cerr << "Unrecognized chassis system state transition " | 
 | 2259 |                              "request.\n"; | 
 | 2260 |                 throw std::invalid_argument("Unrecognized Transition Request"); | 
 | 2261 |                 return 0; | 
 | 2262 |             } | 
 | 2263 |             resp = requested; | 
 | 2264 |             return 1; | 
 | 2265 |         }); | 
 | 2266 |     power_control::chassisSysIface->register_property( | 
 | 2267 |         "CurrentPowerState", | 
 | 2268 |         std::string(power_control::getChassisState(power_control::powerState))); | 
 | 2269 |     power_control::chassisSysIface->register_property( | 
 | 2270 |         "LastStateChangeTime", power_control::getCurrentTimeMs()); | 
 | 2271 |  | 
 | 2272 |     power_control::chassisSysIface->initialize(); | 
 | 2273 |  | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2274 |     // Buttons Service | 
 | 2275 |     sdbusplus::asio::object_server buttonsServer = | 
 | 2276 |         sdbusplus::asio::object_server(power_control::conn); | 
 | 2277 |  | 
 | 2278 |     // Power Button Interface | 
 | 2279 |     power_control::powerButtonIface = buttonsServer.add_interface( | 
 | 2280 |         "/xyz/openbmc_project/chassis/buttons/power", | 
 | 2281 |         "xyz.openbmc_project.Chassis.Buttons"); | 
 | 2282 |  | 
 | 2283 |     power_control::powerButtonIface->register_property( | 
 | 2284 |         "ButtonMasked", false, [](const bool requested, bool& current) { | 
 | 2285 |             if (requested) | 
 | 2286 |             { | 
 | 2287 |                 if (power_control::powerButtonMask) | 
 | 2288 |                 { | 
 | 2289 |                     return 1; | 
 | 2290 |                 } | 
 | 2291 |                 if (!power_control::setGPIOOutput( | 
| Vijay Khemka | 0dc7d4c | 2019-10-22 12:30:17 -0700 | [diff] [blame] | 2292 |                         power_control::powerOutName, 1, | 
 | 2293 |                         power_control::powerButtonMask)) | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2294 |                 { | 
 | 2295 |                     throw std::runtime_error("Failed to request GPIO"); | 
 | 2296 |                     return 0; | 
 | 2297 |                 } | 
 | 2298 |                 std::cerr << "Power Button Masked.\n"; | 
 | 2299 |             } | 
 | 2300 |             else | 
 | 2301 |             { | 
 | 2302 |                 if (!power_control::powerButtonMask) | 
 | 2303 |                 { | 
 | 2304 |                     return 1; | 
 | 2305 |                 } | 
 | 2306 |                 std::cerr << "Power Button Un-masked\n"; | 
 | 2307 |                 power_control::powerButtonMask.reset(); | 
 | 2308 |             } | 
 | 2309 |             // Update the mask setting | 
 | 2310 |             current = requested; | 
 | 2311 |             return 1; | 
 | 2312 |         }); | 
 | 2313 |  | 
 | 2314 |     // Check power button state | 
 | 2315 |     bool powerButtonPressed = power_control::powerButtonLine.get_value() == 0; | 
 | 2316 |     power_control::powerButtonIface->register_property("ButtonPressed", | 
 | 2317 |                                                        powerButtonPressed); | 
 | 2318 |  | 
 | 2319 |     power_control::powerButtonIface->initialize(); | 
 | 2320 |  | 
 | 2321 |     // Reset Button Interface | 
 | 2322 |     power_control::resetButtonIface = buttonsServer.add_interface( | 
 | 2323 |         "/xyz/openbmc_project/chassis/buttons/reset", | 
 | 2324 |         "xyz.openbmc_project.Chassis.Buttons"); | 
 | 2325 |  | 
 | 2326 |     power_control::resetButtonIface->register_property( | 
 | 2327 |         "ButtonMasked", false, [](const bool requested, bool& current) { | 
 | 2328 |             if (requested) | 
 | 2329 |             { | 
 | 2330 |                 if (power_control::resetButtonMask) | 
 | 2331 |                 { | 
 | 2332 |                     return 1; | 
 | 2333 |                 } | 
 | 2334 |                 if (!power_control::setGPIOOutput( | 
| Vijay Khemka | 0dc7d4c | 2019-10-22 12:30:17 -0700 | [diff] [blame] | 2335 |                         power_control::resetOutName, 1, | 
 | 2336 |                         power_control::resetButtonMask)) | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2337 |                 { | 
 | 2338 |                     throw std::runtime_error("Failed to request GPIO"); | 
 | 2339 |                     return 0; | 
 | 2340 |                 } | 
 | 2341 |                 std::cerr << "Reset Button Masked.\n"; | 
 | 2342 |             } | 
 | 2343 |             else | 
 | 2344 |             { | 
 | 2345 |                 if (!power_control::resetButtonMask) | 
 | 2346 |                 { | 
 | 2347 |                     return 1; | 
 | 2348 |                 } | 
 | 2349 |                 std::cerr << "Reset Button Un-masked\n"; | 
 | 2350 |                 power_control::resetButtonMask.reset(); | 
 | 2351 |             } | 
 | 2352 |             // Update the mask setting | 
 | 2353 |             current = requested; | 
 | 2354 |             return 1; | 
 | 2355 |         }); | 
 | 2356 |  | 
 | 2357 |     // Check reset button state | 
 | 2358 |     bool resetButtonPressed = power_control::resetButtonLine.get_value() == 0; | 
 | 2359 |     power_control::resetButtonIface->register_property("ButtonPressed", | 
 | 2360 |                                                        resetButtonPressed); | 
 | 2361 |  | 
 | 2362 |     power_control::resetButtonIface->initialize(); | 
 | 2363 |  | 
| Vijay Khemka | 33a532d | 2019-11-14 16:50:35 -0800 | [diff] [blame] | 2364 |     if (power_control::nmiButtonLine) | 
 | 2365 |     { | 
 | 2366 |         // NMI Button Interface | 
 | 2367 |         power_control::nmiButtonIface = buttonsServer.add_interface( | 
 | 2368 |             "/xyz/openbmc_project/chassis/buttons/nmi", | 
 | 2369 |             "xyz.openbmc_project.Chassis.Buttons"); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2370 |  | 
| Vijay Khemka | 33a532d | 2019-11-14 16:50:35 -0800 | [diff] [blame] | 2371 |         power_control::nmiButtonIface->register_property( | 
 | 2372 |             "ButtonMasked", false, [](const bool requested, bool& current) { | 
 | 2373 |                 if (power_control::nmiButtonMasked == requested) | 
 | 2374 |                 { | 
 | 2375 |                     // NMI button mask is already set as requested, so no change | 
 | 2376 |                     return 1; | 
 | 2377 |                 } | 
 | 2378 |                 if (requested) | 
 | 2379 |                 { | 
 | 2380 |                     std::cerr << "NMI Button Masked.\n"; | 
 | 2381 |                     power_control::nmiButtonMasked = true; | 
 | 2382 |                 } | 
 | 2383 |                 else | 
 | 2384 |                 { | 
 | 2385 |                     std::cerr << "NMI Button Un-masked.\n"; | 
 | 2386 |                     power_control::nmiButtonMasked = false; | 
 | 2387 |                 } | 
 | 2388 |                 // Update the mask setting | 
 | 2389 |                 current = power_control::nmiButtonMasked; | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2390 |                 return 1; | 
| Vijay Khemka | 33a532d | 2019-11-14 16:50:35 -0800 | [diff] [blame] | 2391 |             }); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2392 |  | 
| Vijay Khemka | 33a532d | 2019-11-14 16:50:35 -0800 | [diff] [blame] | 2393 |         // Check NMI button state | 
 | 2394 |         bool nmiButtonPressed = power_control::nmiButtonLine.get_value() == 0; | 
 | 2395 |         power_control::nmiButtonIface->register_property("ButtonPressed", | 
 | 2396 |                                                          nmiButtonPressed); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2397 |  | 
| Vijay Khemka | 33a532d | 2019-11-14 16:50:35 -0800 | [diff] [blame] | 2398 |         power_control::nmiButtonIface->initialize(); | 
 | 2399 |     } | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2400 |  | 
| Vijay Khemka | 33a532d | 2019-11-14 16:50:35 -0800 | [diff] [blame] | 2401 |     if (power_control::nmiOutLine) | 
 | 2402 |     { | 
 | 2403 |         // NMI out Service | 
 | 2404 |         sdbusplus::asio::object_server nmiOutServer = | 
 | 2405 |             sdbusplus::asio::object_server(power_control::conn); | 
| Chen Yugang | 174ec66 | 2019-08-19 19:58:49 +0800 | [diff] [blame] | 2406 |  | 
| Vijay Khemka | 33a532d | 2019-11-14 16:50:35 -0800 | [diff] [blame] | 2407 |         // NMI out Interface | 
 | 2408 |         power_control::nmiOutIface = | 
 | 2409 |             nmiOutServer.add_interface("/xyz/openbmc_project/control/host0/nmi", | 
 | 2410 |                                        "xyz.openbmc_project.Control.Host.NMI"); | 
 | 2411 |         power_control::nmiOutIface->register_method("NMI", | 
 | 2412 |                                                     power_control::nmiReset); | 
 | 2413 |         power_control::nmiOutIface->initialize(); | 
 | 2414 |     } | 
| Chen Yugang | 174ec66 | 2019-08-19 19:58:49 +0800 | [diff] [blame] | 2415 |  | 
| Vijay Khemka | 33a532d | 2019-11-14 16:50:35 -0800 | [diff] [blame] | 2416 |     if (power_control::idButtonLine) | 
 | 2417 |     { | 
 | 2418 |         // ID Button Interface | 
 | 2419 |         power_control::idButtonIface = buttonsServer.add_interface( | 
 | 2420 |             "/xyz/openbmc_project/chassis/buttons/id", | 
 | 2421 |             "xyz.openbmc_project.Chassis.Buttons"); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2422 |  | 
| Vijay Khemka | 33a532d | 2019-11-14 16:50:35 -0800 | [diff] [blame] | 2423 |         // Check ID button state | 
 | 2424 |         bool idButtonPressed = power_control::idButtonLine.get_value() == 0; | 
 | 2425 |         power_control::idButtonIface->register_property("ButtonPressed", | 
 | 2426 |                                                         idButtonPressed); | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2427 |  | 
| Vijay Khemka | 33a532d | 2019-11-14 16:50:35 -0800 | [diff] [blame] | 2428 |         power_control::idButtonIface->initialize(); | 
 | 2429 |     } | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2430 |  | 
 | 2431 |     // OS State Service | 
 | 2432 |     sdbusplus::asio::object_server osServer = | 
 | 2433 |         sdbusplus::asio::object_server(power_control::conn); | 
 | 2434 |  | 
 | 2435 |     // OS State Interface | 
 | 2436 |     power_control::osIface = osServer.add_interface( | 
 | 2437 |         "/xyz/openbmc_project/state/os", | 
 | 2438 |         "xyz.openbmc_project.State.OperatingSystem.Status"); | 
 | 2439 |  | 
 | 2440 |     // Get the initial OS state based on POST complete | 
 | 2441 |     //      0: Asserted, OS state is "Standby" (ready to boot) | 
 | 2442 |     //      1: De-Asserted, OS state is "Inactive" | 
 | 2443 |     std::string osState = power_control::postCompleteLine.get_value() > 0 | 
 | 2444 |                               ? "Inactive" | 
 | 2445 |                               : "Standby"; | 
 | 2446 |  | 
 | 2447 |     power_control::osIface->register_property("OperatingSystemState", | 
 | 2448 |                                               std::string(osState)); | 
 | 2449 |  | 
 | 2450 |     power_control::osIface->initialize(); | 
 | 2451 |  | 
| Jason M. Bills | 7d4aaac | 2019-09-19 14:03:44 -0700 | [diff] [blame] | 2452 |     // Restart Cause Service | 
 | 2453 |     sdbusplus::asio::object_server restartCauseServer = | 
 | 2454 |         sdbusplus::asio::object_server(power_control::conn); | 
 | 2455 |  | 
 | 2456 |     // Restart Cause Interface | 
 | 2457 |     power_control::restartCauseIface = restartCauseServer.add_interface( | 
 | 2458 |         "/xyz/openbmc_project/control/host0/restart_cause", | 
 | 2459 |         "xyz.openbmc_project.Control.Host.RestartCause"); | 
 | 2460 |  | 
 | 2461 |     power_control::restartCauseIface->register_property( | 
 | 2462 |         "RestartCause", | 
 | 2463 |         std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown")); | 
 | 2464 |  | 
 | 2465 |     power_control::restartCauseIface->register_property( | 
 | 2466 |         "RequestedRestartCause", | 
 | 2467 |         std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"), | 
 | 2468 |         [](const std::string& requested, std::string& resp) { | 
 | 2469 |             if (requested == | 
 | 2470 |                 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer") | 
 | 2471 |             { | 
 | 2472 |                 power_control::addRestartCause( | 
 | 2473 |                     power_control::RestartCause::watchdog); | 
 | 2474 |             } | 
 | 2475 |             else | 
 | 2476 |             { | 
 | 2477 |                 throw std::invalid_argument( | 
 | 2478 |                     "Unrecognized RestartCause Request"); | 
 | 2479 |                 return 0; | 
 | 2480 |             } | 
 | 2481 |  | 
 | 2482 |             std::cerr << "RestartCause requested: " << requested << "\n"; | 
 | 2483 |             resp = requested; | 
 | 2484 |             return 1; | 
 | 2485 |         }); | 
 | 2486 |  | 
 | 2487 |     power_control::restartCauseIface->initialize(); | 
 | 2488 |  | 
| Yong Li | 8d66021 | 2019-12-27 10:18:10 +0800 | [diff] [blame] | 2489 |     power_control::currentHostStateMonitor(); | 
 | 2490 |  | 
| Ed Tanous | f61ca6f | 2019-08-15 15:09:05 -0700 | [diff] [blame] | 2491 |     power_control::io.run(); | 
 | 2492 |  | 
 | 2493 |     return 0; | 
 | 2494 | } |