blob: 1e1fb0affd56896830a21e8122cba36a6d22fbb8 [file] [log] [blame]
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001/*
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*/
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +030016#include "power_control.hpp"
17
Ed Tanousf61ca6f2019-08-15 15:09:05 -070018#include <sys/sysinfo.h>
19#include <systemd/sd-journal.h>
20
Ed Tanous744e9a92023-02-28 13:35:22 -080021#include <boost/asio/io_context.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070022#include <boost/asio/posix/stream_descriptor.hpp>
Jason M. Billse63dea02020-08-27 12:07:35 -070023#include <boost/asio/steady_timer.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070024#include <boost/container/flat_map.hpp>
Jason M. Bills7d4aaac2019-09-19 14:03:44 -070025#include <boost/container/flat_set.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070026#include <gpiod.hpp>
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053027#include <nlohmann/json.hpp>
Jason M. Billsc46ebb42021-11-10 11:41:31 -080028#include <phosphor-logging/lg2.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070029#include <sdbusplus/asio/object_server.hpp>
Vijay Khemka2b6f4422020-05-29 11:13:23 -070030
31#include <filesystem>
32#include <fstream>
Zev Weissca478552024-06-11 23:45:58 +000033#include <optional>
34#include <regex>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070035#include <string_view>
36
37namespace power_control
38{
Ed Tanous744e9a92023-02-28 13:35:22 -080039static boost::asio::io_context io;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070040std::shared_ptr<sdbusplus::asio::connection> conn;
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +030041PersistentState appState;
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +030042PowerRestoreController powerRestore(io);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053043
44static std::string node = "0";
Andrei Kartashev3efcf372021-12-29 15:32:17 +030045static const std::string appName = "power-control";
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053046
Priyatharshan P70120512020-09-16 18:47:20 +053047enum class DbusConfigType
48{
49 name = 1,
50 path,
51 interface,
52 property
53};
Zev Weissca478552024-06-11 23:45:58 +000054
55// Mandatory config parameters for dbus inputs
Priyatharshan P70120512020-09-16 18:47:20 +053056boost::container::flat_map<DbusConfigType, std::string> dbusParams = {
57 {DbusConfigType::name, "DbusName"},
58 {DbusConfigType::path, "Path"},
59 {DbusConfigType::interface, "Interface"},
60 {DbusConfigType::property, "Property"}};
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053061
Priyatharshan P70120512020-09-16 18:47:20 +053062enum class ConfigType
63{
64 GPIO = 1,
65 DBUS
66};
67
68struct ConfigData
69{
70 std::string name;
71 std::string lineName;
72 std::string dbusName;
73 std::string path;
74 std::string interface;
Zev Weissca478552024-06-11 23:45:58 +000075 std::optional<std::regex> matchRegex;
Jean-Marie Verdun50937e72021-08-31 09:15:49 -070076 bool polarity;
Priyatharshan P70120512020-09-16 18:47:20 +053077 ConfigType type;
78};
79
80static ConfigData powerOutConfig;
81static ConfigData powerOkConfig;
82static ConfigData resetOutConfig;
83static ConfigData nmiOutConfig;
84static ConfigData sioPwrGoodConfig;
85static ConfigData sioOnControlConfig;
86static ConfigData sioS5Config;
87static ConfigData postCompleteConfig;
88static ConfigData powerButtonConfig;
89static ConfigData resetButtonConfig;
90static ConfigData idButtonConfig;
91static ConfigData nmiButtonConfig;
Naveen Moses117c34e2021-05-26 20:10:51 +053092static ConfigData slotPowerConfig;
Konstantin Aladyshevcfc4d252021-11-18 11:08:38 +030093static ConfigData hpmStbyEnConfig;
Naveen Moses117c34e2021-05-26 20:10:51 +053094
Priyatharshan P70120512020-09-16 18:47:20 +053095// map for storing list of gpio parameters whose config are to be read from x86
96// power control json config
97boost::container::flat_map<std::string, ConfigData*> powerSignalMap = {
98 {"PowerOut", &powerOutConfig},
99 {"PowerOk", &powerOkConfig},
100 {"ResetOut", &resetOutConfig},
101 {"NMIOut", &nmiOutConfig},
102 {"SioPowerGood", &sioPwrGoodConfig},
103 {"SioOnControl", &sioOnControlConfig},
104 {"SIOS5", &sioS5Config},
105 {"PostComplete", &postCompleteConfig},
106 {"PowerButton", &powerButtonConfig},
107 {"ResetButton", &resetButtonConfig},
108 {"IdButton", &idButtonConfig},
Naveen Moses117c34e2021-05-26 20:10:51 +0530109 {"NMIButton", &nmiButtonConfig},
Konstantin Aladyshevcfc4d252021-11-18 11:08:38 +0300110 {"SlotPower", &slotPowerConfig},
111 {"HpmStbyEn", &hpmStbyEnConfig}};
Priyatharshan P70120512020-09-16 18:47:20 +0530112
113static std::string hostDbusName = "xyz.openbmc_project.State.Host";
114static std::string chassisDbusName = "xyz.openbmc_project.State.Chassis";
115static std::string osDbusName = "xyz.openbmc_project.State.OperatingSystem";
116static std::string buttonDbusName = "xyz.openbmc_project.Chassis.Buttons";
117static std::string nmiDbusName = "xyz.openbmc_project.Control.Host.NMI";
118static std::string rstCauseDbusName =
119 "xyz.openbmc_project.Control.Host.RestartCause";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700120static std::shared_ptr<sdbusplus::asio::dbus_interface> hostIface;
121static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700122#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -0700123static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSysIface;
Naveen Moses117c34e2021-05-26 20:10:51 +0530124static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSlotIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700125#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700126static std::shared_ptr<sdbusplus::asio::dbus_interface> powerButtonIface;
127static std::shared_ptr<sdbusplus::asio::dbus_interface> resetButtonIface;
128static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiButtonIface;
129static std::shared_ptr<sdbusplus::asio::dbus_interface> osIface;
130static std::shared_ptr<sdbusplus::asio::dbus_interface> idButtonIface;
Chen Yugang174ec662019-08-19 19:58:49 +0800131static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiOutIface;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700132static std::shared_ptr<sdbusplus::asio::dbus_interface> restartCauseIface;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700133
134static gpiod::line powerButtonMask;
135static gpiod::line resetButtonMask;
136static bool nmiButtonMasked = false;
Matt Simmering58e379d2022-09-23 14:45:50 -0700137#if IGNORE_SOFT_RESETS_DURING_POST
138static bool ignoreNextSoftReset = false;
139#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700140
Priyatharshan P70120512020-09-16 18:47:20 +0530141// This map contains all timer values that are to be read from json config
142boost::container::flat_map<std::string, int> TimerMap = {
Jason M. Billsaeefe042021-09-08 14:56:11 -0700143 {"PowerPulseMs", 200},
144 {"ForceOffPulseMs", 15000},
145 {"ResetPulseMs", 500},
146 {"PowerCycleMs", 5000},
147 {"SioPowerGoodWatchdogMs", 1000},
148 {"PsPowerOKWatchdogMs", 8000},
149 {"GracefulPowerOffS", (5 * 60)},
150 {"WarmResetCheckMs", 500},
151 {"PowerOffSaveMs", 7000},
Michal Orzeledd211e2022-10-28 13:10:16 +0200152 {"SlotPowerCycleMs", 200},
153 {"DbusGetPropertyRetry", 1000}};
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700154
155static bool nmiEnabled = true;
Olivier FAURAXd7ea2832023-04-14 14:08:02 +0000156static bool nmiWhenPoweredOff = true;
Priyatharshan P19c47a32020-08-12 18:16:43 +0530157static bool sioEnabled = true;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700158
159// Timers
160// Time holding GPIOs asserted
161static boost::asio::steady_timer gpioAssertTimer(io);
162// Time between off and on during a power cycle
163static boost::asio::steady_timer powerCycleTimer(io);
164// Time OS gracefully powering off
165static boost::asio::steady_timer gracefulPowerOffTimer(io);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700166// Time the warm reset check
167static boost::asio::steady_timer warmResetCheckTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700168// Time power supply power OK assertion on power-on
169static boost::asio::steady_timer psPowerOKWatchdogTimer(io);
170// Time SIO power good assertion on power-on
171static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io);
172// Time power-off state save for power loss tracking
173static boost::asio::steady_timer powerStateSaveTimer(io);
174// POH timer
175static boost::asio::steady_timer pohCounterTimer(io);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700176// Time when to allow restart cause updates
177static boost::asio::steady_timer restartCauseTimer(io);
Naveen Moses117c34e2021-05-26 20:10:51 +0530178static boost::asio::steady_timer slotPowerCycleTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700179
Michal Orzeledd211e2022-10-28 13:10:16 +0200180// Map containing timers used for D-Bus get-property retries
181static boost::container::flat_map<std::string, boost::asio::steady_timer>
182 dBusRetryTimers;
183
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700184// GPIO Lines and Event Descriptors
185static gpiod::line psPowerOKLine;
186static boost::asio::posix::stream_descriptor psPowerOKEvent(io);
187static gpiod::line sioPowerGoodLine;
188static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io);
189static gpiod::line sioOnControlLine;
190static boost::asio::posix::stream_descriptor sioOnControlEvent(io);
191static gpiod::line sioS5Line;
192static boost::asio::posix::stream_descriptor sioS5Event(io);
193static gpiod::line powerButtonLine;
194static boost::asio::posix::stream_descriptor powerButtonEvent(io);
195static gpiod::line resetButtonLine;
196static boost::asio::posix::stream_descriptor resetButtonEvent(io);
197static gpiod::line nmiButtonLine;
198static boost::asio::posix::stream_descriptor nmiButtonEvent(io);
199static gpiod::line idButtonLine;
200static boost::asio::posix::stream_descriptor idButtonEvent(io);
201static gpiod::line postCompleteLine;
202static boost::asio::posix::stream_descriptor postCompleteEvent(io);
203static gpiod::line nmiOutLine;
Naveen Moses117c34e2021-05-26 20:10:51 +0530204static gpiod::line slotPowerLine;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700205
206static constexpr uint8_t beepPowerFail = 8;
207
208static void beep(const uint8_t& beepPriority)
209{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800210 lg2::info("Beep with priority: {BEEP_PRIORITY}", "BEEP_PRIORITY",
211 beepPriority);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700212
213 conn->async_method_call(
214 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -0500215 if (ec)
216 {
217 lg2::error(
218 "beep returned error with async_method_call (ec = {ERROR_MSG})",
219 "ERROR_MSG", ec.message());
220 return;
221 }
Patrick Williamsd394c882023-10-20 11:18:44 -0500222 },
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700223 "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
224 "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
225}
226
Tim Lee86239182021-12-23 11:46:01 +0800227enum class OperatingSystemStateStage
228{
229 Inactive,
230 Standby,
231};
Matt Simmering58e379d2022-09-23 14:45:50 -0700232static OperatingSystemStateStage operatingSystemState;
Tim Lee86239182021-12-23 11:46:01 +0800233static constexpr std::string_view
234 getOperatingSystemStateStage(const OperatingSystemStateStage stage)
235{
236 switch (stage)
237 {
238 case OperatingSystemStateStage::Inactive:
239 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
240 break;
241 case OperatingSystemStateStage::Standby:
242 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Standby";
243 break;
244 default:
245 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
246 break;
247 }
248};
249static void setOperatingSystemState(const OperatingSystemStateStage stage)
250{
Matt Simmering58e379d2022-09-23 14:45:50 -0700251 operatingSystemState = stage;
252#if IGNORE_SOFT_RESETS_DURING_POST
253 // If POST complete has asserted set ignoreNextSoftReset to false to avoid
254 // masking soft resets after POST
255 if (operatingSystemState == OperatingSystemStateStage::Standby)
256 {
257 ignoreNextSoftReset = false;
258 }
259#endif
Tim Lee86239182021-12-23 11:46:01 +0800260 osIface->set_property("OperatingSystemState",
261 std::string(getOperatingSystemStateStage(stage)));
262
263 lg2::info("Moving os state to {STATE} stage", "STATE",
264 getOperatingSystemStateStage(stage));
265}
266
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700267enum class PowerState
268{
269 on,
270 waitForPSPowerOK,
271 waitForSIOPowerGood,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700272 off,
273 transitionToOff,
274 gracefulTransitionToOff,
275 cycleOff,
276 transitionToCycleOff,
277 gracefulTransitionToCycleOff,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700278 checkForWarmReset,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700279};
280static PowerState powerState;
281static std::string getPowerStateName(PowerState state)
282{
283 switch (state)
284 {
285 case PowerState::on:
286 return "On";
287 break;
288 case PowerState::waitForPSPowerOK:
289 return "Wait for Power Supply Power OK";
290 break;
291 case PowerState::waitForSIOPowerGood:
292 return "Wait for SIO Power Good";
293 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700294 case PowerState::off:
295 return "Off";
296 break;
297 case PowerState::transitionToOff:
298 return "Transition to Off";
299 break;
300 case PowerState::gracefulTransitionToOff:
301 return "Graceful Transition to Off";
302 break;
303 case PowerState::cycleOff:
304 return "Power Cycle Off";
305 break;
306 case PowerState::transitionToCycleOff:
307 return "Transition to Power Cycle Off";
308 break;
309 case PowerState::gracefulTransitionToCycleOff:
310 return "Graceful Transition to Power Cycle Off";
311 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700312 case PowerState::checkForWarmReset:
313 return "Check for Warm Reset";
314 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700315 default:
316 return "unknown state: " + std::to_string(static_cast<int>(state));
317 break;
318 }
319}
320static void logStateTransition(const PowerState state)
321{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800322 lg2::info("Host{HOST}: Moving to \"{STATE}\" state", "HOST", node, "STATE",
323 getPowerStateName(state));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700324}
325
326enum class Event
327{
328 psPowerOKAssert,
329 psPowerOKDeAssert,
330 sioPowerGoodAssert,
331 sioPowerGoodDeAssert,
332 sioS5Assert,
333 sioS5DeAssert,
Jason M. Billsfb957332021-01-28 13:18:46 -0800334 pltRstAssert,
335 pltRstDeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700336 postCompleteAssert,
337 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700338 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700339 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700340 powerCycleTimerExpired,
341 psPowerOKWatchdogTimerExpired,
342 sioPowerGoodWatchdogTimerExpired,
343 gracefulPowerOffTimerExpired,
344 powerOnRequest,
345 powerOffRequest,
346 powerCycleRequest,
347 resetRequest,
348 gracefulPowerOffRequest,
349 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700350 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700351};
352static std::string getEventName(Event event)
353{
354 switch (event)
355 {
356 case Event::psPowerOKAssert:
357 return "power supply power OK assert";
358 break;
359 case Event::psPowerOKDeAssert:
360 return "power supply power OK de-assert";
361 break;
362 case Event::sioPowerGoodAssert:
363 return "SIO power good assert";
364 break;
365 case Event::sioPowerGoodDeAssert:
366 return "SIO power good de-assert";
367 break;
368 case Event::sioS5Assert:
369 return "SIO S5 assert";
370 break;
371 case Event::sioS5DeAssert:
372 return "SIO S5 de-assert";
373 break;
Jason M. Billsfb957332021-01-28 13:18:46 -0800374 case Event::pltRstAssert:
375 return "PLT_RST assert";
376 break;
377 case Event::pltRstDeAssert:
378 return "PLT_RST de-assert";
379 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700380 case Event::postCompleteAssert:
381 return "POST Complete assert";
382 break;
383 case Event::postCompleteDeAssert:
384 return "POST Complete de-assert";
385 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700386 case Event::powerButtonPressed:
387 return "power button pressed";
388 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700389 case Event::resetButtonPressed:
390 return "reset button pressed";
391 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700392 case Event::powerCycleTimerExpired:
393 return "power cycle timer expired";
394 break;
395 case Event::psPowerOKWatchdogTimerExpired:
396 return "power supply power OK watchdog timer expired";
397 break;
398 case Event::sioPowerGoodWatchdogTimerExpired:
399 return "SIO power good watchdog timer expired";
400 break;
401 case Event::gracefulPowerOffTimerExpired:
402 return "graceful power-off timer expired";
403 break;
404 case Event::powerOnRequest:
405 return "power-on request";
406 break;
407 case Event::powerOffRequest:
408 return "power-off request";
409 break;
410 case Event::powerCycleRequest:
411 return "power-cycle request";
412 break;
413 case Event::resetRequest:
414 return "reset request";
415 break;
416 case Event::gracefulPowerOffRequest:
417 return "graceful power-off request";
418 break;
419 case Event::gracefulPowerCycleRequest:
420 return "graceful power-cycle request";
421 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700422 case Event::warmResetDetected:
423 return "warm reset detected";
424 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700425 default:
426 return "unknown event: " + std::to_string(static_cast<int>(event));
427 break;
428 }
429}
430static void logEvent(const std::string_view stateHandler, const Event event)
431{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800432 lg2::info("{STATE_HANDLER}: {EVENT} event received", "STATE_HANDLER",
433 stateHandler, "EVENT", getEventName(event));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700434}
435
436// Power state handlers
437static void powerStateOn(const Event event);
438static void powerStateWaitForPSPowerOK(const Event event);
439static void powerStateWaitForSIOPowerGood(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700440static void powerStateOff(const Event event);
441static void powerStateTransitionToOff(const Event event);
442static void powerStateGracefulTransitionToOff(const Event event);
443static void powerStateCycleOff(const Event event);
444static void powerStateTransitionToCycleOff(const Event event);
445static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700446static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700447
448static std::function<void(const Event)> getPowerStateHandler(PowerState state)
449{
450 switch (state)
451 {
452 case PowerState::on:
453 return powerStateOn;
454 break;
455 case PowerState::waitForPSPowerOK:
456 return powerStateWaitForPSPowerOK;
457 break;
458 case PowerState::waitForSIOPowerGood:
459 return powerStateWaitForSIOPowerGood;
460 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700461 case PowerState::off:
462 return powerStateOff;
463 break;
464 case PowerState::transitionToOff:
465 return powerStateTransitionToOff;
466 break;
467 case PowerState::gracefulTransitionToOff:
468 return powerStateGracefulTransitionToOff;
469 break;
470 case PowerState::cycleOff:
471 return powerStateCycleOff;
472 break;
473 case PowerState::transitionToCycleOff:
474 return powerStateTransitionToCycleOff;
475 break;
476 case PowerState::gracefulTransitionToCycleOff:
477 return powerStateGracefulTransitionToCycleOff;
478 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700479 case PowerState::checkForWarmReset:
480 return powerStateCheckForWarmReset;
481 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700482 default:
Zev Weiss047bcb52020-08-20 21:28:11 +0000483 return nullptr;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700484 break;
485 }
486};
487
488static void sendPowerControlEvent(const Event event)
489{
490 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
491 if (handler == nullptr)
492 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800493 lg2::error("Failed to find handler for power state: {STATE}", "STATE",
494 static_cast<int>(powerState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700495 return;
496 }
497 handler(event);
498}
499
500static uint64_t getCurrentTimeMs()
501{
502 struct timespec time = {};
503
504 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
505 {
506 return 0;
507 }
508 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
509 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
510
511 return currentTimeMs;
512}
513
514static constexpr std::string_view getHostState(const PowerState state)
515{
516 switch (state)
517 {
518 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700519 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700520 case PowerState::gracefulTransitionToCycleOff:
521 return "xyz.openbmc_project.State.Host.HostState.Running";
522 break;
523 case PowerState::waitForPSPowerOK:
524 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700525 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700526 case PowerState::transitionToOff:
527 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700528 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700529 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700530 return "xyz.openbmc_project.State.Host.HostState.Off";
531 break;
532 default:
533 return "";
534 break;
535 }
536};
537static constexpr std::string_view getChassisState(const PowerState state)
538{
539 switch (state)
540 {
541 case PowerState::on:
542 case PowerState::transitionToOff:
543 case PowerState::gracefulTransitionToOff:
544 case PowerState::transitionToCycleOff:
545 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700546 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700547 return "xyz.openbmc_project.State.Chassis.PowerState.On";
548 break;
549 case PowerState::waitForPSPowerOK:
550 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700551 case PowerState::off:
552 case PowerState::cycleOff:
553 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
554 break;
555 default:
556 return "";
557 break;
558 }
559};
Naveen Moses117c34e2021-05-26 20:10:51 +0530560#ifdef CHASSIS_SYSTEM_RESET
561enum class SlotPowerState
562{
563 on,
564 off,
565};
566static SlotPowerState slotPowerState;
567static constexpr std::string_view getSlotState(const SlotPowerState state)
568{
569 switch (state)
570 {
571 case SlotPowerState::on:
572 return "xyz.openbmc_project.State.Chassis.PowerState.On";
573 break;
574 case SlotPowerState::off:
575 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
576 break;
577 default:
578 return "";
579 break;
580 }
581};
582static void setSlotPowerState(const SlotPowerState state)
583{
584 slotPowerState = state;
585 chassisSlotIface->set_property("CurrentPowerState",
586 std::string(getSlotState(slotPowerState)));
587 chassisSlotIface->set_property("LastStateChangeTime", getCurrentTimeMs());
588}
589#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700590static void savePowerState(const PowerState state)
591{
592 powerStateSaveTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -0700593 std::chrono::milliseconds(TimerMap["PowerOffSaveMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700594 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
595 if (ec)
596 {
597 // operation_aborted is expected if timer is canceled before
598 // completion.
599 if (ec != boost::asio::error::operation_aborted)
600 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800601 lg2::error("Power-state save async_wait failed: {ERROR_MSG}",
602 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700603 }
604 return;
605 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300606 appState.set(PersistentState::Params::PowerState,
607 std::string{getChassisState(state)});
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700608 });
609}
610static void setPowerState(const PowerState state)
611{
612 powerState = state;
613 logStateTransition(state);
614
615 hostIface->set_property("CurrentHostState",
616 std::string(getHostState(powerState)));
617
618 chassisIface->set_property("CurrentPowerState",
619 std::string(getChassisState(powerState)));
620 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
621
622 // Save the power state for the restore policy
623 savePowerState(state);
624}
625
626enum class RestartCause
627{
628 command,
629 resetButton,
630 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700631 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700632 powerPolicyOn,
633 powerPolicyRestore,
634 softReset,
635};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700636static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700637static std::string getRestartCause(RestartCause cause)
638{
639 switch (cause)
640 {
641 case RestartCause::command:
642 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
643 break;
644 case RestartCause::resetButton:
645 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
646 break;
647 case RestartCause::powerButton:
648 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
649 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700650 case RestartCause::watchdog:
651 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
652 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700653 case RestartCause::powerPolicyOn:
Jason M. Bills418ce112021-09-08 15:15:05 -0700654 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyAlwaysOn";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700655 break;
656 case RestartCause::powerPolicyRestore:
Jason M. Bills418ce112021-09-08 15:15:05 -0700657 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyPreviousState";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700658 break;
659 case RestartCause::softReset:
660 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
661 break;
662 default:
663 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
664 break;
665 }
666}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700667static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700668{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700669 // Add this to the set of causes for this restart
670 causeSet.insert(cause);
671}
672static void clearRestartCause()
673{
674 // Clear the set for the next restart
675 causeSet.clear();
676}
677static void setRestartCauseProperty(const std::string& cause)
678{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800679 lg2::info("RestartCause set to {RESTART_CAUSE}", "RESTART_CAUSE", cause);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700680 restartCauseIface->set_property("RestartCause", cause);
681}
Rashmi RV89f61312020-01-22 15:41:50 +0530682
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300683#ifdef USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +0530684static void resetACBootProperty()
685{
686 if ((causeSet.contains(RestartCause::command)) ||
687 (causeSet.contains(RestartCause::softReset)))
688 {
689 conn->async_method_call(
690 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -0500691 if (ec)
692 {
693 lg2::error("failed to reset ACBoot property");
694 }
Patrick Williamsd394c882023-10-20 11:18:44 -0500695 },
Rashmi RV89f61312020-01-22 15:41:50 +0530696 "xyz.openbmc_project.Settings",
697 "/xyz/openbmc_project/control/host0/ac_boot",
698 "org.freedesktop.DBus.Properties", "Set",
699 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
700 std::variant<std::string>{"False"});
701 }
702}
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300703#endif // USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +0530704
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700705static void setRestartCause()
706{
707 // Determine the actual restart cause based on the set of causes
708 std::string restartCause =
709 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
710 if (causeSet.contains(RestartCause::watchdog))
711 {
712 restartCause = getRestartCause(RestartCause::watchdog);
713 }
714 else if (causeSet.contains(RestartCause::command))
715 {
716 restartCause = getRestartCause(RestartCause::command);
717 }
718 else if (causeSet.contains(RestartCause::resetButton))
719 {
720 restartCause = getRestartCause(RestartCause::resetButton);
721 }
722 else if (causeSet.contains(RestartCause::powerButton))
723 {
724 restartCause = getRestartCause(RestartCause::powerButton);
725 }
726 else if (causeSet.contains(RestartCause::powerPolicyOn))
727 {
728 restartCause = getRestartCause(RestartCause::powerPolicyOn);
729 }
730 else if (causeSet.contains(RestartCause::powerPolicyRestore))
731 {
732 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
733 }
734 else if (causeSet.contains(RestartCause::softReset))
735 {
Matt Simmering58e379d2022-09-23 14:45:50 -0700736#if IGNORE_SOFT_RESETS_DURING_POST
737 if (ignoreNextSoftReset)
738 {
739 ignoreNextSoftReset = false;
740 return;
741 }
742#endif
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700743 restartCause = getRestartCause(RestartCause::softReset);
744 }
745
746 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700747}
748
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700749static void systemPowerGoodFailedLog()
750{
751 sd_journal_send(
752 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
753 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
754 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700755 TimerMap["SioPowerGoodWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700756}
757
758static void psPowerOKFailedLog()
759{
760 sd_journal_send(
761 "MESSAGE=PowerControl: power supply power good failed to assert",
762 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
763 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700764 TimerMap["PsPowerOKWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700765}
766
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700767static void powerRestorePolicyLog()
768{
769 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
770 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
771 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
772}
773
774static void powerButtonPressLog()
775{
776 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
777 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
778 "OpenBMC.0.1.PowerButtonPressed", NULL);
779}
780
781static void resetButtonPressLog()
782{
783 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
784 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
785 "OpenBMC.0.1.ResetButtonPressed", NULL);
786}
787
788static void nmiButtonPressLog()
789{
790 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
791 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
792 "OpenBMC.0.1.NMIButtonPressed", NULL);
793}
794
795static void nmiDiagIntLog()
796{
797 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
798 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
799 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
800}
801
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300802PersistentState::PersistentState()
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700803{
804 // create the power control directory if it doesn't exist
805 std::error_code ec;
806 if (!(std::filesystem::create_directories(powerControlDir, ec)))
807 {
808 if (ec.value() != 0)
809 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800810 lg2::error("failed to create {DIR_NAME}: {ERROR_MSG}", "DIR_NAME",
811 powerControlDir.string(), "ERROR_MSG", ec.message());
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300812 throw std::runtime_error("Failed to create state directory");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700813 }
814 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300815
816 // read saved state, it's ok, if the file doesn't exists
817 std::ifstream appStateStream(powerControlDir / stateFile);
818 if (!appStateStream.is_open())
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700819 {
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300820 lg2::info("Cannot open state file \'{PATH}\'", "PATH",
821 std::string(powerControlDir / stateFile));
822 stateData = nlohmann::json({});
823 return;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700824 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300825 try
826 {
827 appStateStream >> stateData;
828 if (stateData.is_discarded())
829 {
830 lg2::info("Cannot parse state file \'{PATH}\'", "PATH",
831 std::string(powerControlDir / stateFile));
832 stateData = nlohmann::json({});
833 return;
834 }
835 }
836 catch (const std::exception& ex)
837 {
838 lg2::info("Cannot read state file \'{PATH}\'", "PATH",
839 std::string(powerControlDir / stateFile));
840 stateData = nlohmann::json({});
841 return;
842 }
843}
844PersistentState::~PersistentState()
845{
846 saveState();
847}
848const std::string PersistentState::get(Params parameter)
849{
850 auto val = stateData.find(getName(parameter));
851 if (val != stateData.end())
852 {
853 return val->get<std::string>();
854 }
855 return getDefault(parameter);
856}
857void PersistentState::set(Params parameter, const std::string& value)
858{
859 stateData[getName(parameter)] = value;
860 saveState();
861}
862
863const std::string PersistentState::getName(const Params parameter)
864{
865 switch (parameter)
866 {
867 case Params::PowerState:
868 return "PowerState";
869 }
870 return "";
871}
872const std::string PersistentState::getDefault(const Params parameter)
873{
874 switch (parameter)
875 {
876 case Params::PowerState:
877 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
878 }
879 return "";
880}
881void PersistentState::saveState()
882{
883 std::ofstream appStateStream(powerControlDir / stateFile, std::ios::trunc);
884 if (!appStateStream.is_open())
885 {
886 lg2::error("Cannot write state file \'{PATH}\'", "PATH",
887 std::string(powerControlDir / stateFile));
888 return;
889 }
890 appStateStream << stateData.dump(indentationSize);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700891}
892
Patrick Williams48aa1f02023-05-10 07:50:30 -0500893static constexpr const char* setingsService = "xyz.openbmc_project.Settings";
894static constexpr const char* powerRestorePolicyIface =
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300895 "xyz.openbmc_project.Control.Power.RestorePolicy";
896#ifdef USE_ACBOOT
Patrick Williams48aa1f02023-05-10 07:50:30 -0500897static constexpr const char* powerACBootObject =
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300898 "/xyz/openbmc_project/control/host0/ac_boot";
Patrick Williams48aa1f02023-05-10 07:50:30 -0500899static constexpr const char* powerACBootIface =
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300900 "xyz.openbmc_project.Common.ACBoot";
901#endif // USE_ACBOOT
902
903namespace match_rules = sdbusplus::bus::match::rules;
904
905static int powerRestoreConfigHandler(sd_bus_message* m, void* context,
906 sd_bus_error*)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700907{
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300908 if (context == nullptr || m == nullptr)
909 {
910 throw std::runtime_error("Invalid match");
911 }
Patrick Williams439b9c32022-07-22 19:26:53 -0500912 sdbusplus::message_t message(m);
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300913 PowerRestoreController* powerRestore =
914 static_cast<PowerRestoreController*>(context);
915
916 if (std::string(message.get_member()) == "InterfacesAdded")
917 {
918 sdbusplus::message::object_path path;
919 boost::container::flat_map<std::string, dbusPropertiesList> data;
920
921 message.read(path, data);
922
923 for (auto& [iface, properties] : data)
924 {
925 if ((iface == powerRestorePolicyIface)
926#ifdef USE_ACBOOT
927 || (iface == powerACBootIface)
928#endif // USE_ACBOOT
929 )
930 {
931 powerRestore->setProperties(properties);
932 }
933 }
934 }
935 else if (std::string(message.get_member()) == "PropertiesChanged")
936 {
937 std::string interfaceName;
938 dbusPropertiesList propertiesChanged;
939
940 message.read(interfaceName, propertiesChanged);
941
942 powerRestore->setProperties(propertiesChanged);
943 }
944 return 1;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700945}
946
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300947void PowerRestoreController::run()
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700948{
Patrick Williams48aa1f02023-05-10 07:50:30 -0500949 std::string powerRestorePolicyObject = "/xyz/openbmc_project/control/host" +
950 node + "/power_restore_policy";
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300951 powerRestorePolicyLog();
952 // this list only needs to be created once
953 if (matches.empty())
954 {
955 matches.emplace_back(
956 *conn,
957 match_rules::interfacesAdded() +
958 match_rules::argNpath(0, powerRestorePolicyObject) +
959 match_rules::sender(setingsService),
960 powerRestoreConfigHandler, this);
961#ifdef USE_ACBOOT
962 matches.emplace_back(*conn,
963 match_rules::interfacesAdded() +
964 match_rules::argNpath(0, powerACBootObject) +
965 match_rules::sender(setingsService),
966 powerRestoreConfigHandler, this);
967 matches.emplace_back(*conn,
968 match_rules::propertiesChanged(powerACBootObject,
969 powerACBootIface) +
970 match_rules::sender(setingsService),
971 powerRestoreConfigHandler, this);
972#endif // USE_ACBOOT
973 }
974
975 // Check if it's already on DBus
976 conn->async_method_call(
977 [this](boost::system::error_code ec,
978 const dbusPropertiesList properties) {
Patrick Williams48aa1f02023-05-10 07:50:30 -0500979 if (ec)
980 {
981 return;
982 }
983 setProperties(properties);
Patrick Williamsd394c882023-10-20 11:18:44 -0500984 },
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300985 setingsService, powerRestorePolicyObject,
986 "org.freedesktop.DBus.Properties", "GetAll", powerRestorePolicyIface);
987
988#ifdef USE_ACBOOT
989 // Check if it's already on DBus
990 conn->async_method_call(
991 [this](boost::system::error_code ec,
992 const dbusPropertiesList properties) {
Patrick Williams48aa1f02023-05-10 07:50:30 -0500993 if (ec)
994 {
995 return;
996 }
997 setProperties(properties);
Patrick Williamsd394c882023-10-20 11:18:44 -0500998 },
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300999 setingsService, powerACBootObject, "org.freedesktop.DBus.Properties",
1000 "GetAll", powerACBootIface);
1001#endif
1002}
1003
1004void PowerRestoreController::setProperties(const dbusPropertiesList& props)
1005{
1006 for (auto& [property, propValue] : props)
1007 {
1008 if (property == "PowerRestorePolicy")
1009 {
1010 const std::string* value = std::get_if<std::string>(&propValue);
1011 if (value == nullptr)
1012 {
1013 lg2::error("Unable to read Power Restore Policy");
1014 continue;
1015 }
1016 powerRestorePolicy = *value;
1017 }
1018 else if (property == "PowerRestoreDelay")
1019 {
1020 const uint64_t* value = std::get_if<uint64_t>(&propValue);
1021 if (value == nullptr)
1022 {
1023 lg2::error("Unable to read Power Restore Delay");
1024 continue;
1025 }
1026 powerRestoreDelay = *value / 1000000; // usec to sec
1027 }
1028#ifdef USE_ACBOOT
1029 else if (property == "ACBoot")
1030 {
1031 const std::string* value = std::get_if<std::string>(&propValue);
1032 if (value == nullptr)
1033 {
1034 lg2::error("Unable to read AC Boot status");
1035 continue;
1036 }
1037 acBoot = *value;
1038 }
1039#endif // USE_ACBOOT
1040 }
1041 invokeIfReady();
1042}
1043
1044void PowerRestoreController::invokeIfReady()
1045{
1046 if ((powerRestorePolicy.empty()) || (powerRestoreDelay < 0))
1047 {
1048 return;
1049 }
1050#ifdef USE_ACBOOT
1051 if (acBoot.empty() || acBoot == "Unknown")
1052 {
1053 return;
1054 }
1055#endif
1056
1057 matches.clear();
1058 if (!timerFired)
1059 {
1060 // Calculate the delay from now to meet the requested delay
1061 // Subtract the approximate uboot time
1062 static constexpr const int ubootSeconds = 20;
1063 int delay = powerRestoreDelay - ubootSeconds;
1064 // Subtract the time since boot
1065 struct sysinfo info = {};
1066 if (sysinfo(&info) == 0)
1067 {
1068 delay -= info.uptime;
1069 }
1070
1071 if (delay > 0)
1072 {
1073 powerRestoreTimer.expires_after(std::chrono::seconds(delay));
1074 lg2::info("Power Restore delay of {DELAY} seconds started", "DELAY",
1075 delay);
Patrick Williams48aa1f02023-05-10 07:50:30 -05001076 powerRestoreTimer.async_wait(
1077 [this](const boost::system::error_code ec) {
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001078 if (ec)
1079 {
1080 // operation_aborted is expected if timer is canceled before
1081 // completion.
1082 if (ec == boost::asio::error::operation_aborted)
1083 {
1084 return;
1085 }
1086 lg2::error(
1087 "power restore policy async_wait failed: {ERROR_MSG}",
1088 "ERROR_MSG", ec.message());
1089 }
1090 else
1091 {
1092 lg2::info("Power Restore delay timer expired");
1093 }
1094 invoke();
1095 });
1096 timerFired = true;
1097 }
1098 else
1099 {
1100 invoke();
1101 }
1102 }
1103}
1104
1105void PowerRestoreController::invoke()
1106{
1107 // we want to run Power Restore only once
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001108 if (policyInvoked)
1109 {
1110 return;
1111 }
1112 policyInvoked = true;
1113
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001114 lg2::info("Invoking Power Restore Policy {POLICY}", "POLICY",
1115 powerRestorePolicy);
1116 if (powerRestorePolicy ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001117 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
1118 {
1119 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001120 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001121 }
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001122 else if (powerRestorePolicy ==
Jason M. Bills418ce112021-09-08 15:15:05 -07001123 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore")
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001124 {
1125 if (wasPowerDropped())
1126 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001127 lg2::info("Power was dropped, restoring Host On state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001128 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001129 setRestartCauseProperty(
1130 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001131 }
1132 else
1133 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001134 lg2::info("No power drop, restoring Host Off state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001135 }
1136 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -07001137 // We're done with the previous power state for the restore policy, so store
1138 // the current state
1139 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001140}
1141
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001142bool PowerRestoreController::wasPowerDropped()
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001143{
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001144 std::string state = appState.get(PersistentState::Params::PowerState);
1145 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001146}
1147
Zev Weiss676ef2c2021-09-02 21:54:02 -05001148static void waitForGPIOEvent(const std::string& name,
1149 const std::function<void(bool)>& eventHandler,
1150 gpiod::line& line,
1151 boost::asio::posix::stream_descriptor& event)
1152{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001153 event.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1154 [&name, eventHandler, &line,
1155 &event](const boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001156 if (ec)
1157 {
1158 lg2::error("{GPIO_NAME} fd handler error: {ERROR_MSG}", "GPIO_NAME",
1159 name, "ERROR_MSG", ec.message());
1160 // TODO: throw here to force power-control to
1161 // restart?
1162 return;
1163 }
1164 gpiod::line_event line_event = line.event_read();
1165 eventHandler(line_event.event_type == gpiod::line_event::RISING_EDGE);
1166 waitForGPIOEvent(name, eventHandler, line, event);
1167 });
Zev Weiss676ef2c2021-09-02 21:54:02 -05001168}
1169
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001170static bool requestGPIOEvents(
Zev Weiss676ef2c2021-09-02 21:54:02 -05001171 const std::string& name, const std::function<void(bool)>& handler,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001172 gpiod::line& gpioLine,
1173 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
1174{
1175 // Find the GPIO line
1176 gpioLine = gpiod::find_line(name);
1177 if (!gpioLine)
1178 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001179 lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001180 return false;
1181 }
1182
1183 try
1184 {
Andrei Kartashev3efcf372021-12-29 15:32:17 +03001185 gpioLine.request({appName, gpiod::line_request::EVENT_BOTH_EDGES, {}});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001186 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001187 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001188 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001189 lg2::error("Failed to request events for {GPIO_NAME}: {ERROR}",
1190 "GPIO_NAME", name, "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001191 return false;
1192 }
1193
1194 int gpioLineFd = gpioLine.event_get_fd();
1195 if (gpioLineFd < 0)
1196 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001197 lg2::error("Failed to get {GPIO_NAME} fd", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001198 return false;
1199 }
1200
1201 gpioEventDescriptor.assign(gpioLineFd);
1202
Zev Weiss676ef2c2021-09-02 21:54:02 -05001203 waitForGPIOEvent(name, handler, gpioLine, gpioEventDescriptor);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001204 return true;
1205}
1206
1207static bool setGPIOOutput(const std::string& name, const int value,
1208 gpiod::line& gpioLine)
1209{
1210 // Find the GPIO line
1211 gpioLine = gpiod::find_line(name);
1212 if (!gpioLine)
1213 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001214 lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001215 return false;
1216 }
1217
1218 // Request GPIO output to specified value
1219 try
1220 {
Andrei Kartashev3efcf372021-12-29 15:32:17 +03001221 gpioLine.request({appName, gpiod::line_request::DIRECTION_OUTPUT, {}},
1222 value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001223 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001224 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001225 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001226 lg2::error("Failed to request {GPIO_NAME} output: {ERROR}", "GPIO_NAME",
1227 name, "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001228 return false;
1229 }
1230
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001231 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1232 "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001233 return true;
1234}
1235
1236static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1237 const std::string& name, const int value,
1238 const int durationMs)
1239{
1240 // Set the masked GPIO line to the specified value
1241 maskedGPIOLine.set_value(value);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001242 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1243 "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001244 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001245 gpioAssertTimer.async_wait(
1246 [maskedGPIOLine, value, name](const boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001247 // Set the masked GPIO line back to the opposite value
1248 maskedGPIOLine.set_value(!value);
1249 lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
1250 if (ec)
1251 {
1252 // operation_aborted is expected if timer is canceled before
1253 // completion.
1254 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001255 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001256 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1257 "GPIO_NAME", name, "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001258 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05001259 }
1260 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001261 return 0;
1262}
1263
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001264static int setGPIOOutputForMs(const ConfigData& config, const int value,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001265 const int durationMs)
1266{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001267 // If the requested GPIO is masked, use the mask line to set the output
1268 if (powerButtonMask && config.lineName == powerOutConfig.lineName)
1269 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001270 return setMaskedGPIOOutputForMs(powerButtonMask, config.lineName, value,
1271 durationMs);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001272 }
1273 if (resetButtonMask && config.lineName == resetOutConfig.lineName)
1274 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001275 return setMaskedGPIOOutputForMs(resetButtonMask, config.lineName, value,
1276 durationMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001277 }
1278
1279 // No mask set, so request and set the GPIO normally
1280 gpiod::line gpioLine;
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001281 if (!setGPIOOutput(config.lineName, value, gpioLine))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001282 {
1283 return -1;
1284 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001285 const std::string name = config.lineName;
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001286
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001287 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001288 gpioAssertTimer.async_wait(
1289 [gpioLine, value, name](const boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001290 // Set the GPIO line back to the opposite value
1291 gpioLine.set_value(!value);
1292 lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
1293 if (ec)
1294 {
1295 // operation_aborted is expected if timer is canceled before
1296 // completion.
1297 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001298 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001299 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1300 "GPIO_NAME", name, "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001301 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05001302 }
1303 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001304 return 0;
1305}
1306
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001307static int assertGPIOForMs(const ConfigData& config, const int durationMs)
1308{
1309 return setGPIOOutputForMs(config, config.polarity, durationMs);
1310}
1311
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001312static void powerOn()
1313{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001314 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001315}
Naveen Moses117c34e2021-05-26 20:10:51 +05301316#ifdef CHASSIS_SYSTEM_RESET
1317static int slotPowerOn()
1318{
1319 if (power_control::slotPowerState != power_control::SlotPowerState::on)
1320 {
Naveen Moses117c34e2021-05-26 20:10:51 +05301321 slotPowerLine.set_value(1);
1322
1323 if (slotPowerLine.get_value() > 0)
1324 {
1325 setSlotPowerState(SlotPowerState::on);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001326 lg2::info("Slot Power is switched On\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301327 }
1328 else
1329 {
1330 return -1;
1331 }
1332 }
1333 else
1334 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001335 lg2::info("Slot Power is already in 'On' state\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301336 return -1;
1337 }
1338 return 0;
1339}
1340static int slotPowerOff()
1341{
1342 if (power_control::slotPowerState != power_control::SlotPowerState::off)
1343 {
1344 slotPowerLine.set_value(0);
1345
1346 if (!(slotPowerLine.get_value() > 0))
1347 {
1348 setSlotPowerState(SlotPowerState::off);
1349 setPowerState(PowerState::off);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001350 lg2::info("Slot Power is switched Off\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301351 }
1352 else
1353 {
1354 return -1;
1355 }
1356 }
1357 else
1358 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001359 lg2::info("Slot Power is already in 'Off' state\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301360 return -1;
1361 }
1362 return 0;
1363}
1364static void slotPowerCycle()
1365{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001366 lg2::info("Slot Power Cycle started\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301367 slotPowerOff();
1368 slotPowerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001369 std::chrono::milliseconds(TimerMap["SlotPowerCycleMs"]));
Naveen Moses117c34e2021-05-26 20:10:51 +05301370 slotPowerCycleTimer.async_wait([](const boost::system::error_code ec) {
1371 if (ec)
1372 {
1373 if (ec != boost::asio::error::operation_aborted)
1374 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001375 lg2::error(
1376 "Slot Power cycle timer async_wait failed: {ERROR_MSG}",
1377 "ERROR_MSG", ec.message());
Naveen Moses117c34e2021-05-26 20:10:51 +05301378 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001379 lg2::info("Slot Power cycle timer canceled\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301380 return;
1381 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001382 lg2::info("Slot Power cycle timer completed\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301383 slotPowerOn();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001384 lg2::info("Slot Power Cycle Completed\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301385 });
1386}
1387#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001388static void gracefulPowerOff()
1389{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001390 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001391}
1392
1393static void forcePowerOff()
1394{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001395 if (assertGPIOForMs(powerOutConfig, TimerMap["ForceOffPulseMs"]) < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001396 {
1397 return;
1398 }
1399
Jason M. Billsc6961b62021-10-21 14:08:02 -07001400 // If the force off timer expires, then the power-button override failed
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001401 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1402 if (ec)
1403 {
1404 // operation_aborted is expected if timer is canceled before
1405 // completion.
1406 if (ec != boost::asio::error::operation_aborted)
1407 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001408 lg2::error("Force power off async_wait failed: {ERROR_MSG}",
1409 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001410 }
1411 return;
1412 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001413
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001414 lg2::error("Power-button override failed. Not sure what to do now.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001415 });
1416}
1417
1418static void reset()
1419{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001420 assertGPIOForMs(resetOutConfig, TimerMap["ResetPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001421}
1422
1423static void gracefulPowerOffTimerStart()
1424{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001425 lg2::info("Graceful power-off timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001426 gracefulPowerOffTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001427 std::chrono::seconds(TimerMap["GracefulPowerOffS"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001428 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1429 if (ec)
1430 {
1431 // operation_aborted is expected if timer is canceled before
1432 // completion.
1433 if (ec != boost::asio::error::operation_aborted)
1434 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001435 lg2::error("Graceful power-off async_wait failed: {ERROR_MSG}",
1436 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001437 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001438 lg2::info("Graceful power-off timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001439 return;
1440 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001441 lg2::info("Graceful power-off timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001442 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1443 });
1444}
1445
1446static void powerCycleTimerStart()
1447{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001448 lg2::info("Power-cycle timer started");
Priyatharshan P70120512020-09-16 18:47:20 +05301449 powerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001450 std::chrono::milliseconds(TimerMap["PowerCycleMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001451 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1452 if (ec)
1453 {
1454 // operation_aborted is expected if timer is canceled before
1455 // completion.
1456 if (ec != boost::asio::error::operation_aborted)
1457 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001458 lg2::error("Power-cycle async_wait failed: {ERROR_MSG}",
1459 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001460 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001461 lg2::info("Power-cycle timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001462 return;
1463 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001464 lg2::info("Power-cycle timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001465 sendPowerControlEvent(Event::powerCycleTimerExpired);
1466 });
1467}
1468
1469static void psPowerOKWatchdogTimerStart()
1470{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001471 lg2::info("power supply power OK watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001472 psPowerOKWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001473 std::chrono::milliseconds(TimerMap["PsPowerOKWatchdogMs"]));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001474 psPowerOKWatchdogTimer.async_wait([](const boost::system::error_code ec) {
1475 if (ec)
1476 {
1477 // operation_aborted is expected if timer is canceled before
1478 // completion.
1479 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001480 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001481 lg2::error(
1482 "power supply power OK watchdog async_wait failed: {ERROR_MSG}",
1483 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001484 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001485 lg2::info("power supply power OK watchdog timer canceled");
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001486 return;
1487 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001488 lg2::info("power supply power OK watchdog timer expired");
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001489 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1490 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001491}
1492
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001493static void warmResetCheckTimerStart()
1494{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001495 lg2::info("Warm reset check timer started");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001496 warmResetCheckTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001497 std::chrono::milliseconds(TimerMap["WarmResetCheckMs"]));
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001498 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1499 if (ec)
1500 {
1501 // operation_aborted is expected if timer is canceled before
1502 // completion.
1503 if (ec != boost::asio::error::operation_aborted)
1504 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001505 lg2::error("Warm reset check async_wait failed: {ERROR_MSG}",
1506 "ERROR_MSG", ec.message());
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001507 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001508 lg2::info("Warm reset check timer canceled");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001509 return;
1510 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001511 lg2::info("Warm reset check timer completed");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001512 sendPowerControlEvent(Event::warmResetDetected);
1513 });
1514}
1515
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001516static void pohCounterTimerStart()
1517{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001518 lg2::info("POH timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001519 // Set the time-out as 1 hour, to align with POH command in ipmid
1520 pohCounterTimer.expires_after(std::chrono::hours(1));
1521 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1522 if (ec)
1523 {
1524 // operation_aborted is expected if timer is canceled before
1525 // completion.
1526 if (ec != boost::asio::error::operation_aborted)
1527 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001528 lg2::error("POH timer async_wait failed: {ERROR_MSG}",
1529 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001530 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001531 lg2::info("POH timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001532 return;
1533 }
1534
1535 if (getHostState(powerState) !=
1536 "xyz.openbmc_project.State.Host.HostState.Running")
1537 {
1538 return;
1539 }
1540
1541 conn->async_method_call(
1542 [](boost::system::error_code ec,
1543 const std::variant<uint32_t>& pohCounterProperty) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001544 if (ec)
1545 {
1546 lg2::error("error getting poh counter");
1547 return;
1548 }
1549 const uint32_t* pohCounter =
1550 std::get_if<uint32_t>(&pohCounterProperty);
1551 if (pohCounter == nullptr)
1552 {
1553 lg2::error("unable to read poh counter");
1554 return;
1555 }
1556
1557 conn->async_method_call(
1558 [](boost::system::error_code ec) {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001559 if (ec)
1560 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001561 lg2::error("failed to set poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001562 }
Patrick Williamsd394c882023-10-20 11:18:44 -05001563 },
Patrick Williams48aa1f02023-05-10 07:50:30 -05001564 "xyz.openbmc_project.Settings",
1565 "/xyz/openbmc_project/state/chassis0",
1566 "org.freedesktop.DBus.Properties", "Set",
1567 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1568 std::variant<uint32_t>(*pohCounter + 1));
Patrick Williamsd394c882023-10-20 11:18:44 -05001569 },
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001570 "xyz.openbmc_project.Settings",
1571 "/xyz/openbmc_project/state/chassis0",
1572 "org.freedesktop.DBus.Properties", "Get",
1573 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1574
1575 pohCounterTimerStart();
1576 });
1577}
1578
1579static void currentHostStateMonitor()
1580{
Yong Li8d660212019-12-27 10:18:10 +08001581 if (getHostState(powerState) ==
1582 "xyz.openbmc_project.State.Host.HostState.Running")
1583 {
1584 pohCounterTimerStart();
1585 // Clear the restart cause set for the next restart
1586 clearRestartCause();
1587 }
1588 else
1589 {
1590 pohCounterTimer.cancel();
1591 // Set the restart cause set for this restart
1592 setRestartCause();
1593 }
1594
Patrick Williams48aa1f02023-05-10 07:50:30 -05001595 static auto match =
1596 sdbusplus::bus::match_t(*conn,
1597 "type='signal',member='PropertiesChanged', "
1598 "interface='org.freedesktop.DBus.Properties', "
1599 "arg0='xyz.openbmc_project.State.Host'",
1600 [](sdbusplus::message_t& message) {
1601 std::string intfName;
1602 std::map<std::string, std::variant<std::string>> properties;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001603
Patrick Williams48aa1f02023-05-10 07:50:30 -05001604 try
1605 {
1606 message.read(intfName, properties);
1607 }
1608 catch (const std::exception& e)
1609 {
1610 lg2::error("Unable to read host state: {ERROR}", "ERROR", e);
1611 return;
1612 }
1613 if (properties.empty())
1614 {
1615 lg2::error("ERROR: Empty PropertiesChanged signal received");
1616 return;
1617 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001618
Patrick Williams48aa1f02023-05-10 07:50:30 -05001619 // We only want to check for CurrentHostState
1620 if (properties.begin()->first != "CurrentHostState")
1621 {
1622 return;
1623 }
1624 std::string* currentHostState =
1625 std::get_if<std::string>(&(properties.begin()->second));
1626 if (currentHostState == nullptr)
1627 {
1628 lg2::error("{PROPERTY} property invalid", "PROPERTY",
1629 properties.begin()->first);
1630 return;
1631 }
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001632
Patrick Williams48aa1f02023-05-10 07:50:30 -05001633 if (*currentHostState ==
1634 "xyz.openbmc_project.State.Host.HostState.Running")
1635 {
1636 pohCounterTimerStart();
1637 // Clear the restart cause set for the next restart
1638 clearRestartCause();
1639 sd_journal_send("MESSAGE=Host system DC power is on", "PRIORITY=%i",
1640 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
1641 "OpenBMC.0.1.DCPowerOn", NULL);
1642 }
1643 else
1644 {
1645 pohCounterTimer.cancel();
1646 // POST_COMPLETE GPIO event is not working in some platforms
1647 // when power state is changed to OFF. This resulted in
1648 // 'OperatingSystemState' to stay at 'Standby', even though
1649 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1650 // if HostState is trurned to OFF.
1651 setOperatingSystemState(OperatingSystemStateStage::Inactive);
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301652
Patrick Williams48aa1f02023-05-10 07:50:30 -05001653 // Set the restart cause set for this restart
1654 setRestartCause();
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001655#ifdef USE_ACBOOT
Patrick Williams48aa1f02023-05-10 07:50:30 -05001656 resetACBootProperty();
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001657#endif // USE_ACBOOT
Patrick Williams48aa1f02023-05-10 07:50:30 -05001658 sd_journal_send("MESSAGE=Host system DC power is off",
1659 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
1660 "OpenBMC.0.1.DCPowerOff", NULL);
1661 }
Patrick Williamsd394c882023-10-20 11:18:44 -05001662 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001663}
1664
1665static void sioPowerGoodWatchdogTimerStart()
1666{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001667 lg2::info("SIO power good watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001668 sioPowerGoodWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001669 std::chrono::milliseconds(TimerMap["SioPowerGoodWatchdogMs"]));
Patrick Williams48aa1f02023-05-10 07:50:30 -05001670 sioPowerGoodWatchdogTimer.async_wait(
1671 [](const boost::system::error_code ec) {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001672 if (ec)
1673 {
1674 // operation_aborted is expected if timer is canceled before
1675 // completion.
1676 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001677 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001678 lg2::error(
1679 "SIO power good watchdog async_wait failed: {ERROR_MSG}",
1680 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001681 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001682 lg2::info("SIO power good watchdog timer canceled");
1683 return;
1684 }
1685 lg2::info("SIO power good watchdog timer completed");
1686 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1687 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001688}
1689
1690static void powerStateOn(const Event event)
1691{
1692 logEvent(__FUNCTION__, event);
1693 switch (event)
1694 {
1695 case Event::psPowerOKDeAssert:
1696 setPowerState(PowerState::off);
1697 // DC power is unexpectedly lost, beep
1698 beep(beepPowerFail);
1699 break;
1700 case Event::sioS5Assert:
1701 setPowerState(PowerState::transitionToOff);
Matt Simmering58e379d2022-09-23 14:45:50 -07001702#if IGNORE_SOFT_RESETS_DURING_POST
1703 // Only recognize soft resets once host gets past POST COMPLETE
1704 if (operatingSystemState != OperatingSystemStateStage::Standby)
1705 {
1706 ignoreNextSoftReset = true;
1707 }
1708#endif
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001709 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001710 break;
Jason M. Billsfb957332021-01-28 13:18:46 -08001711#if USE_PLT_RST
1712 case Event::pltRstAssert:
1713#else
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001714 case Event::postCompleteDeAssert:
Jason M. Billsfb957332021-01-28 13:18:46 -08001715#endif
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001716 setPowerState(PowerState::checkForWarmReset);
Matt Simmering58e379d2022-09-23 14:45:50 -07001717#if IGNORE_SOFT_RESETS_DURING_POST
1718 // Only recognize soft resets once host gets past POST COMPLETE
1719 if (operatingSystemState != OperatingSystemStateStage::Standby)
1720 {
1721 ignoreNextSoftReset = true;
1722 }
1723#endif
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001724 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001725 warmResetCheckTimerStart();
1726 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001727 case Event::powerButtonPressed:
1728 setPowerState(PowerState::gracefulTransitionToOff);
1729 gracefulPowerOffTimerStart();
1730 break;
1731 case Event::powerOffRequest:
1732 setPowerState(PowerState::transitionToOff);
1733 forcePowerOff();
1734 break;
1735 case Event::gracefulPowerOffRequest:
1736 setPowerState(PowerState::gracefulTransitionToOff);
1737 gracefulPowerOffTimerStart();
1738 gracefulPowerOff();
1739 break;
1740 case Event::powerCycleRequest:
1741 setPowerState(PowerState::transitionToCycleOff);
1742 forcePowerOff();
1743 break;
1744 case Event::gracefulPowerCycleRequest:
1745 setPowerState(PowerState::gracefulTransitionToCycleOff);
1746 gracefulPowerOffTimerStart();
1747 gracefulPowerOff();
1748 break;
Jayanth Othayothdc0bab92024-02-07 07:24:35 -06001749 case Event::resetButtonPressed:
1750 setPowerState(PowerState::checkForWarmReset);
1751 warmResetCheckTimerStart();
1752 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001753 case Event::resetRequest:
1754 reset();
1755 break;
1756 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001757 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001758 break;
1759 }
1760}
1761
1762static void powerStateWaitForPSPowerOK(const Event event)
1763{
1764 logEvent(__FUNCTION__, event);
1765 switch (event)
1766 {
1767 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301768 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001769 // Cancel any GPIO assertions held during the transition
1770 gpioAssertTimer.cancel();
1771 psPowerOKWatchdogTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301772 if (sioEnabled == true)
1773 {
1774 sioPowerGoodWatchdogTimerStart();
1775 setPowerState(PowerState::waitForSIOPowerGood);
1776 }
1777 else
1778 {
1779 setPowerState(PowerState::on);
1780 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001781 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301782 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001783 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001784 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001785 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001786 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001787 case Event::sioPowerGoodAssert:
1788 psPowerOKWatchdogTimer.cancel();
1789 setPowerState(PowerState::on);
1790 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001791 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001792 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001793 break;
1794 }
1795}
1796
1797static void powerStateWaitForSIOPowerGood(const Event event)
1798{
1799 logEvent(__FUNCTION__, event);
1800 switch (event)
1801 {
1802 case Event::sioPowerGoodAssert:
1803 sioPowerGoodWatchdogTimer.cancel();
1804 setPowerState(PowerState::on);
1805 break;
1806 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001807 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001808 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001809 break;
1810 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001811 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001812 break;
1813 }
1814}
1815
1816static void powerStateOff(const Event event)
1817{
1818 logEvent(__FUNCTION__, event);
1819 switch (event)
1820 {
1821 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301822 {
1823 if (sioEnabled == true)
1824 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001825 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301826 setPowerState(PowerState::waitForSIOPowerGood);
1827 }
1828 else
1829 {
1830 setPowerState(PowerState::on);
1831 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001832 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301833 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001834 case Event::sioS5DeAssert:
Jason M. Billsfe159032022-09-01 16:03:37 -07001835 psPowerOKWatchdogTimerStart();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001836 setPowerState(PowerState::waitForPSPowerOK);
1837 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001838 case Event::sioPowerGoodAssert:
1839 setPowerState(PowerState::on);
1840 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001841 case Event::powerButtonPressed:
1842 psPowerOKWatchdogTimerStart();
1843 setPowerState(PowerState::waitForPSPowerOK);
1844 break;
1845 case Event::powerOnRequest:
1846 psPowerOKWatchdogTimerStart();
1847 setPowerState(PowerState::waitForPSPowerOK);
1848 powerOn();
1849 break;
1850 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001851 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001852 break;
1853 }
1854}
1855
1856static void powerStateTransitionToOff(const Event event)
1857{
1858 logEvent(__FUNCTION__, event);
1859 switch (event)
1860 {
1861 case Event::psPowerOKDeAssert:
1862 // Cancel any GPIO assertions held during the transition
1863 gpioAssertTimer.cancel();
1864 setPowerState(PowerState::off);
1865 break;
1866 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001867 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001868 break;
1869 }
1870}
1871
1872static void powerStateGracefulTransitionToOff(const Event event)
1873{
1874 logEvent(__FUNCTION__, event);
1875 switch (event)
1876 {
1877 case Event::psPowerOKDeAssert:
1878 gracefulPowerOffTimer.cancel();
1879 setPowerState(PowerState::off);
1880 break;
1881 case Event::gracefulPowerOffTimerExpired:
1882 setPowerState(PowerState::on);
1883 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001884 case Event::powerOffRequest:
1885 gracefulPowerOffTimer.cancel();
1886 setPowerState(PowerState::transitionToOff);
1887 forcePowerOff();
1888 break;
1889 case Event::powerCycleRequest:
1890 gracefulPowerOffTimer.cancel();
1891 setPowerState(PowerState::transitionToCycleOff);
1892 forcePowerOff();
1893 break;
1894 case Event::resetRequest:
1895 gracefulPowerOffTimer.cancel();
1896 setPowerState(PowerState::on);
1897 reset();
1898 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001899 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001900 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001901 break;
1902 }
1903}
1904
1905static void powerStateCycleOff(const Event event)
1906{
1907 logEvent(__FUNCTION__, event);
1908 switch (event)
1909 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001910 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301911 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001912 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301913 if (sioEnabled == true)
1914 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001915 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301916 setPowerState(PowerState::waitForSIOPowerGood);
1917 }
1918 else
1919 {
1920 setPowerState(PowerState::on);
1921 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001922 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301923 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001924 case Event::sioS5DeAssert:
1925 powerCycleTimer.cancel();
Jason M. Billsfe159032022-09-01 16:03:37 -07001926 psPowerOKWatchdogTimerStart();
Jason M. Bills35aa6652020-04-30 16:24:55 -07001927 setPowerState(PowerState::waitForPSPowerOK);
1928 break;
1929 case Event::powerButtonPressed:
1930 powerCycleTimer.cancel();
1931 psPowerOKWatchdogTimerStart();
1932 setPowerState(PowerState::waitForPSPowerOK);
1933 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001934 case Event::powerCycleTimerExpired:
1935 psPowerOKWatchdogTimerStart();
1936 setPowerState(PowerState::waitForPSPowerOK);
1937 powerOn();
1938 break;
1939 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001940 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001941 break;
1942 }
1943}
1944
1945static void powerStateTransitionToCycleOff(const Event event)
1946{
1947 logEvent(__FUNCTION__, event);
1948 switch (event)
1949 {
1950 case Event::psPowerOKDeAssert:
1951 // Cancel any GPIO assertions held during the transition
1952 gpioAssertTimer.cancel();
1953 setPowerState(PowerState::cycleOff);
1954 powerCycleTimerStart();
1955 break;
1956 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001957 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001958 break;
1959 }
1960}
1961
1962static void powerStateGracefulTransitionToCycleOff(const Event event)
1963{
1964 logEvent(__FUNCTION__, event);
1965 switch (event)
1966 {
1967 case Event::psPowerOKDeAssert:
1968 gracefulPowerOffTimer.cancel();
1969 setPowerState(PowerState::cycleOff);
1970 powerCycleTimerStart();
1971 break;
1972 case Event::gracefulPowerOffTimerExpired:
1973 setPowerState(PowerState::on);
1974 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001975 case Event::powerOffRequest:
1976 gracefulPowerOffTimer.cancel();
1977 setPowerState(PowerState::transitionToOff);
1978 forcePowerOff();
1979 break;
1980 case Event::powerCycleRequest:
1981 gracefulPowerOffTimer.cancel();
1982 setPowerState(PowerState::transitionToCycleOff);
1983 forcePowerOff();
1984 break;
1985 case Event::resetRequest:
1986 gracefulPowerOffTimer.cancel();
1987 setPowerState(PowerState::on);
1988 reset();
1989 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001990 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001991 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001992 break;
1993 }
1994}
1995
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001996static void powerStateCheckForWarmReset(const Event event)
1997{
1998 logEvent(__FUNCTION__, event);
1999 switch (event)
2000 {
2001 case Event::sioS5Assert:
2002 warmResetCheckTimer.cancel();
2003 setPowerState(PowerState::transitionToOff);
2004 break;
2005 case Event::warmResetDetected:
2006 setPowerState(PowerState::on);
2007 break;
P.K. Lee344dae82019-11-27 16:35:05 +08002008 case Event::psPowerOKDeAssert:
2009 warmResetCheckTimer.cancel();
2010 setPowerState(PowerState::off);
2011 // DC power is unexpectedly lost, beep
2012 beep(beepPowerFail);
2013 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002014 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002015 lg2::info("No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002016 break;
2017 }
2018}
2019
Zev Weiss584aa132021-09-02 19:21:52 -05002020static void psPowerOKHandler(bool state)
2021{
Zev Weissedc86f32024-05-07 01:44:33 +00002022 Event powerControlEvent = (state == powerOkConfig.polarity)
2023 ? Event::psPowerOKAssert
2024 : Event::psPowerOKDeAssert;
Zev Weiss584aa132021-09-02 19:21:52 -05002025 sendPowerControlEvent(powerControlEvent);
2026}
2027
Zev Weiss584aa132021-09-02 19:21:52 -05002028static void sioPowerGoodHandler(bool state)
2029{
Zev Weissedc86f32024-05-07 01:44:33 +00002030 Event powerControlEvent = (state == sioPwrGoodConfig.polarity)
2031 ? Event::sioPowerGoodAssert
2032 : Event::sioPowerGoodDeAssert;
Zev Weiss584aa132021-09-02 19:21:52 -05002033 sendPowerControlEvent(powerControlEvent);
2034}
2035
Zev Weiss584aa132021-09-02 19:21:52 -05002036static void sioOnControlHandler(bool state)
2037{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002038 lg2::info("SIO_ONCONTROL value changed: {VALUE}", "VALUE",
2039 static_cast<int>(state));
Zev Weiss584aa132021-09-02 19:21:52 -05002040}
2041
Zev Weiss584aa132021-09-02 19:21:52 -05002042static void sioS5Handler(bool state)
2043{
Zev Weissedc86f32024-05-07 01:44:33 +00002044 Event powerControlEvent = (state == sioS5Config.polarity)
2045 ? Event::sioS5Assert
2046 : Event::sioS5DeAssert;
Zev Weiss584aa132021-09-02 19:21:52 -05002047 sendPowerControlEvent(powerControlEvent);
2048}
2049
Zev Weiss584aa132021-09-02 19:21:52 -05002050static void powerButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002051{
Zev Weissedc86f32024-05-07 01:44:33 +00002052 bool asserted = state == powerButtonConfig.polarity;
2053 powerButtonIface->set_property("ButtonPressed", asserted);
2054 if (asserted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002055 {
2056 powerButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002057 if (!powerButtonMask)
2058 {
2059 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002060 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002061 }
2062 else
2063 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002064 lg2::info("power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002065 }
2066 }
Zev Weiss584aa132021-09-02 19:21:52 -05002067}
2068
Zev Weiss584aa132021-09-02 19:21:52 -05002069static void resetButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002070{
Zev Weissedc86f32024-05-07 01:44:33 +00002071 bool asserted = state == resetButtonConfig.polarity;
2072 resetButtonIface->set_property("ButtonPressed", asserted);
2073 if (asserted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002074 {
2075 resetButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002076 if (!resetButtonMask)
2077 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002078 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002079 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002080 }
2081 else
2082 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002083 lg2::info("reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002084 }
2085 }
Zev Weiss584aa132021-09-02 19:21:52 -05002086}
2087
Vijay Khemka04175c22020-10-09 14:28:11 -07002088#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002089static constexpr auto systemdBusname = "org.freedesktop.systemd1";
2090static constexpr auto systemdPath = "/org/freedesktop/systemd1";
2091static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
2092static constexpr auto systemTargetName = "chassis-system-reset.target";
2093
2094void systemReset()
2095{
2096 conn->async_method_call(
2097 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002098 if (ec)
2099 {
2100 lg2::error("Failed to call chassis system reset: {ERR}", "ERR",
2101 ec.message());
2102 }
Patrick Williamsd394c882023-10-20 11:18:44 -05002103 },
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002104 systemdBusname, systemdPath, systemdInterface, "StartUnit",
2105 systemTargetName, "replace");
2106}
Vijay Khemka04175c22020-10-09 14:28:11 -07002107#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002108
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002109static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002110{
2111 conn->async_method_call(
2112 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002113 if (ec)
2114 {
2115 lg2::error("failed to set NMI source");
2116 }
Patrick Williamsd394c882023-10-20 11:18:44 -05002117 },
Chen Yugang303bd582019-11-01 08:45:06 +08002118 "xyz.openbmc_project.Settings",
2119 "/xyz/openbmc_project/Chassis/Control/NMISource",
2120 "org.freedesktop.DBus.Properties", "Set",
2121 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
2122 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002123}
2124
2125static void nmiReset(void)
2126{
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002127 const static constexpr int nmiOutPulseTimeMs = 200;
2128
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002129 lg2::info("NMI out action");
Jian Zhang461a1662022-09-22 11:29:01 +08002130 nmiOutLine.set_value(nmiOutConfig.polarity);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002131 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME",
Jian Zhang461a1662022-09-22 11:29:01 +08002132 nmiOutConfig.lineName, "GPIO_VALUE", nmiOutConfig.polarity);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002133 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2134 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2135 // restore the NMI_OUT GPIO line back to the opposite value
Jian Zhang461a1662022-09-22 11:29:01 +08002136 nmiOutLine.set_value(!nmiOutConfig.polarity);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002137 lg2::info("{GPIO_NAME} released", "GPIO_NAME", nmiOutConfig.lineName);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002138 if (ec)
2139 {
2140 // operation_aborted is expected if timer is canceled before
2141 // completion.
2142 if (ec != boost::asio::error::operation_aborted)
2143 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002144 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
2145 "GPIO_NAME", nmiOutConfig.lineName, "ERROR_MSG",
2146 ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002147 }
2148 }
2149 });
2150 // log to redfish
2151 nmiDiagIntLog();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002152 lg2::info("NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002153 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002154 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002155}
2156
2157static void nmiSourcePropertyMonitor(void)
2158{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002159 lg2::info("NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002160
Patrick Williams439b9c32022-07-22 19:26:53 -05002161 static std::unique_ptr<sdbusplus::bus::match_t> nmiSourceMatch =
2162 std::make_unique<sdbusplus::bus::match_t>(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002163 *conn,
2164 "type='signal',interface='org.freedesktop.DBus.Properties',"
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002165 "member='PropertiesChanged',"
2166 "arg0namespace='xyz.openbmc_project.Chassis.Control.NMISource'",
Patrick Williams439b9c32022-07-22 19:26:53 -05002167 [](sdbusplus::message_t& msg) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002168 std::string interfaceName;
2169 boost::container::flat_map<std::string, std::variant<bool, std::string>>
2170 propertiesChanged;
2171 std::string state;
2172 bool value = true;
2173 try
2174 {
2175 msg.read(interfaceName, propertiesChanged);
2176 if (propertiesChanged.begin()->first == "Enabled")
2177 {
2178 value = std::get<bool>(propertiesChanged.begin()->second);
2179 lg2::info("NMI Enabled propertiesChanged value: {VALUE}",
2180 "VALUE", value);
2181 nmiEnabled = value;
2182 if (nmiEnabled)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002183 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002184 nmiReset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002185 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05002186 }
2187 }
2188 catch (const std::exception& e)
2189 {
2190 lg2::error("Unable to read NMI source: {ERROR}", "ERROR", e);
2191 return;
2192 }
Patrick Williamsd394c882023-10-20 11:18:44 -05002193 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002194}
2195
2196static void setNmiSource()
2197{
2198 conn->async_method_call(
2199 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002200 if (ec)
2201 {
2202 lg2::error("failed to set NMI source");
2203 }
Patrick Williamsd394c882023-10-20 11:18:44 -05002204 },
Chen Yugang303bd582019-11-01 08:45:06 +08002205 "xyz.openbmc_project.Settings",
2206 "/xyz/openbmc_project/Chassis/Control/NMISource",
2207 "org.freedesktop.DBus.Properties", "Set",
2208 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
Jason M. Bills418ce112021-09-08 15:15:05 -07002209 std::variant<std::string>{
Tim Lee6af569f2024-03-11 17:32:42 +08002210 "xyz.openbmc_project.Chassis.Control.NMISource.BMCSourceSignal.FrontPanelButton"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002211 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002212 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002213}
2214
Zev Weiss584aa132021-09-02 19:21:52 -05002215static void nmiButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002216{
Olivier FAURAXd7ea2832023-04-14 14:08:02 +00002217 // Don't handle event if host not running and config doesn't force it
2218 if (!nmiWhenPoweredOff &&
2219 getHostState(powerState) !=
2220 "xyz.openbmc_project.State.Host.HostState.Running")
2221 {
2222 return;
2223 }
Zev Weissedc86f32024-05-07 01:44:33 +00002224
2225 bool asserted = state == nmiButtonConfig.polarity;
2226 nmiButtonIface->set_property("ButtonPressed", asserted);
2227 if (asserted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002228 {
2229 nmiButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002230 if (nmiButtonMasked)
2231 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002232 lg2::info("NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002233 }
2234 else
2235 {
2236 setNmiSource();
2237 }
2238 }
Zev Weiss584aa132021-09-02 19:21:52 -05002239}
2240
Zev Weiss584aa132021-09-02 19:21:52 -05002241static void idButtonHandler(bool state)
2242{
Zev Weissedc86f32024-05-07 01:44:33 +00002243 bool asserted = state == idButtonConfig.polarity;
2244 idButtonIface->set_property("ButtonPressed", asserted);
Zev Weiss584aa132021-09-02 19:21:52 -05002245}
2246
Jason M. Billsfb957332021-01-28 13:18:46 -08002247static void pltRstHandler(bool pltRst)
2248{
2249 if (pltRst)
2250 {
2251 sendPowerControlEvent(Event::pltRstDeAssert);
2252 }
2253 else
2254 {
2255 sendPowerControlEvent(Event::pltRstAssert);
2256 }
2257}
2258
Patrick Williams439b9c32022-07-22 19:26:53 -05002259[[maybe_unused]] static void hostMiscHandler(sdbusplus::message_t& msg)
Jason M. Billsfb957332021-01-28 13:18:46 -08002260{
2261 std::string interfaceName;
2262 boost::container::flat_map<std::string, std::variant<bool>>
2263 propertiesChanged;
Jason M. Billsfb957332021-01-28 13:18:46 -08002264 try
2265 {
2266 msg.read(interfaceName, propertiesChanged);
2267 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002268 catch (const std::exception& e)
Jason M. Billsfb957332021-01-28 13:18:46 -08002269 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002270 lg2::error("Unable to read Host Misc status: {ERROR}", "ERROR", e);
Jason M. Billsfb957332021-01-28 13:18:46 -08002271 return;
2272 }
2273 if (propertiesChanged.empty())
2274 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002275 lg2::error("ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002276 return;
2277 }
2278
2279 for (auto& [property, value] : propertiesChanged)
2280 {
2281 if (property == "ESpiPlatformReset")
2282 {
2283 bool* pltRst = std::get_if<bool>(&value);
2284 if (pltRst == nullptr)
2285 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002286 lg2::error("{PROPERTY} property invalid", "PROPERTY", property);
Jason M. Billsfb957332021-01-28 13:18:46 -08002287 return;
2288 }
2289 pltRstHandler(*pltRst);
2290 }
2291 }
2292}
2293
Zev Weiss584aa132021-09-02 19:21:52 -05002294static void postCompleteHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002295{
Zev Weissedc86f32024-05-07 01:44:33 +00002296 bool asserted = state == postCompleteConfig.polarity;
2297 if (asserted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002298 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002299 sendPowerControlEvent(Event::postCompleteAssert);
Tim Lee86239182021-12-23 11:46:01 +08002300 setOperatingSystemState(OperatingSystemStateStage::Standby);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002301 }
2302 else
2303 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002304 sendPowerControlEvent(Event::postCompleteDeAssert);
Tim Lee86239182021-12-23 11:46:01 +08002305 setOperatingSystemState(OperatingSystemStateStage::Inactive);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002306 }
Zev Weiss584aa132021-09-02 19:21:52 -05002307}
2308
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302309static int loadConfigValues()
2310{
2311 const std::string configFilePath =
2312 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2313 ".json";
2314 std::ifstream configFile(configFilePath.c_str());
2315 if (!configFile.is_open())
2316 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002317 lg2::error("loadConfigValues: Cannot open config path \'{PATH}\'",
2318 "PATH", configFilePath);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302319 return -1;
2320 }
Zev Weiss1aa08b22021-09-15 17:06:20 -05002321 auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302322
Priyatharshan P70120512020-09-16 18:47:20 +05302323 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302324 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002325 lg2::error("Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302326 return -1;
2327 }
Priyatharshan P70120512020-09-16 18:47:20 +05302328 auto gpios = jsonData["gpio_configs"];
2329 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302330
Priyatharshan P70120512020-09-16 18:47:20 +05302331 ConfigData* tempGpioData;
2332
2333 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302334 {
Priyatharshan P70120512020-09-16 18:47:20 +05302335 if (!gpioConfig.contains("Name"))
2336 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002337 lg2::error("The 'Name' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302338 return -1;
2339 }
2340
2341 // Iterate through the powersignal map to check if the gpio json config
2342 // entry is valid
2343 std::string gpioName = gpioConfig["Name"];
2344 auto signalMapIter = powerSignalMap.find(gpioName);
2345 if (signalMapIter == powerSignalMap.end())
2346 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002347 lg2::error(
2348 "{GPIO_NAME} is not a recognized power-control signal name",
2349 "GPIO_NAME", gpioName);
Priyatharshan P70120512020-09-16 18:47:20 +05302350 return -1;
2351 }
2352
2353 // assign the power signal name to the corresponding structure reference
2354 // from map then fillup the structure with coressponding json config
2355 // value
2356 tempGpioData = signalMapIter->second;
2357 tempGpioData->name = gpioName;
2358
2359 if (!gpioConfig.contains("Type"))
2360 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002361 lg2::error("The \'Type\' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302362 return -1;
2363 }
2364
2365 std::string signalType = gpioConfig["Type"];
2366 if (signalType == "GPIO")
2367 {
2368 tempGpioData->type = ConfigType::GPIO;
2369 }
2370 else if (signalType == "DBUS")
2371 {
2372 tempGpioData->type = ConfigType::DBUS;
2373 }
2374 else
2375 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002376 lg2::error("{TYPE} is not a recognized power-control signal type",
2377 "TYPE", signalType);
Priyatharshan P70120512020-09-16 18:47:20 +05302378 return -1;
2379 }
2380
2381 if (tempGpioData->type == ConfigType::GPIO)
2382 {
2383 if (gpioConfig.contains("LineName"))
2384 {
2385 tempGpioData->lineName = gpioConfig["LineName"];
2386 }
2387 else
2388 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002389 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002390 "The \'LineName\' field must be defined for GPIO configuration");
Priyatharshan P70120512020-09-16 18:47:20 +05302391 return -1;
2392 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002393 if (gpioConfig.contains("Polarity"))
2394 {
2395 std::string polarity = gpioConfig["Polarity"];
2396 if (polarity == "ActiveLow")
2397 {
2398 tempGpioData->polarity = false;
2399 }
2400 else if (polarity == "ActiveHigh")
2401 {
2402 tempGpioData->polarity = true;
2403 }
2404 else
2405 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002406 lg2::error(
2407 "Polarity defined but not properly setup. Please only ActiveHigh or ActiveLow. Currently set to {POLARITY}",
2408 "POLARITY", polarity);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002409 return -1;
2410 }
2411 }
2412 else
2413 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002414 lg2::error("Polarity field not found for {GPIO_NAME}",
2415 "GPIO_NAME", tempGpioData->lineName);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002416 return -1;
2417 }
Priyatharshan P70120512020-09-16 18:47:20 +05302418 }
2419 else
2420 {
2421 // if dbus based gpio config is defined read and update the dbus
2422 // params corresponding to the gpio config instance
2423 for (auto& [key, dbusParamName] : dbusParams)
2424 {
Logananth Sundararaja4308042021-10-20 11:52:05 +05302425 if (!gpioConfig.contains(dbusParamName))
Priyatharshan P70120512020-09-16 18:47:20 +05302426 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002427 lg2::error(
2428 "The {DBUS_NAME} field must be defined for Dbus configuration ",
2429 "DBUS_NAME", dbusParamName);
Priyatharshan P70120512020-09-16 18:47:20 +05302430 return -1;
2431 }
2432 }
Logananth Sundararaja4308042021-10-20 11:52:05 +05302433 tempGpioData->dbusName =
2434 gpioConfig[dbusParams[DbusConfigType::name]];
2435 tempGpioData->path = gpioConfig[dbusParams[DbusConfigType::path]];
Priyatharshan P70120512020-09-16 18:47:20 +05302436 tempGpioData->interface =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302437 gpioConfig[dbusParams[DbusConfigType::interface]];
Priyatharshan P70120512020-09-16 18:47:20 +05302438 tempGpioData->lineName =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302439 gpioConfig[dbusParams[DbusConfigType::property]];
Zev Weissca478552024-06-11 23:45:58 +00002440
Zev Weissd603dd12024-06-19 21:50:52 +00002441 // dbus-based inputs must be active-high.
2442 tempGpioData->polarity = true;
2443
Zev Weissca478552024-06-11 23:45:58 +00002444 // MatchRegex is optional
2445 auto item = gpioConfig.find("MatchRegex");
2446 if (item != gpioConfig.end())
2447 {
2448 try
2449 {
2450 tempGpioData->matchRegex = std::regex(*item);
2451 }
2452 catch (const std::regex_error& e)
2453 {
2454 lg2::error("Invalid MatchRegex for {NAME}: {ERR}", "NAME",
2455 gpioName, "ERR", e.what());
2456 return -1;
2457 }
2458 }
Priyatharshan P70120512020-09-16 18:47:20 +05302459 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302460 }
2461
Priyatharshan P70120512020-09-16 18:47:20 +05302462 // read and store the timer values from json config to Timer Map
2463 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302464 {
Priyatharshan P70120512020-09-16 18:47:20 +05302465 if (timers.contains(key.c_str()))
2466 {
2467 timerValue = timers[key.c_str()];
2468 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302469 }
2470
Jonathan Doman891bbde2023-05-17 13:58:24 -07002471 // If "events_configs" key is not in json config, fallback to null
2472 auto events = jsonData.value("event_configs",
2473 nlohmann::json(nlohmann::json::value_t::null));
2474 if (events.is_object())
Olivier FAURAXd7ea2832023-04-14 14:08:02 +00002475 {
2476 nmiWhenPoweredOff = events.value("NMIWhenPoweredOff", true);
2477 }
2478
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302479 return 0;
2480}
Zev Weissa8f116a2021-09-01 21:08:30 -05002481
Zev Weissca478552024-06-11 23:45:58 +00002482template <typename T>
2483static std::optional<T> getMessageValue(sdbusplus::message_t& msg,
2484 const std::string& name)
Zev Weissa8f116a2021-09-01 21:08:30 -05002485{
Zev Weissa8f116a2021-09-01 21:08:30 -05002486 std::string event;
Zev Weissca478552024-06-11 23:45:58 +00002487 std::string thresholdInterface;
2488 boost::container::flat_map<std::string, std::variant<T>> propertiesChanged;
2489
2490 msg.read(thresholdInterface, propertiesChanged);
2491 if (propertiesChanged.empty())
2492 {
2493 return std::nullopt;
2494 }
2495
2496 event = propertiesChanged.begin()->first;
2497 if (event.empty() || event != name)
2498 {
2499 return std::nullopt;
2500 }
2501
2502 return std::get<T>(propertiesChanged.begin()->second);
2503}
2504
2505static bool getDbusMsgGPIOState(sdbusplus::message_t& msg,
2506 const ConfigData& config, bool& value)
2507{
Zev Weissa8f116a2021-09-01 21:08:30 -05002508 try
2509 {
Zev Weissca478552024-06-11 23:45:58 +00002510 if (config.matchRegex.has_value())
Zev Weissa8f116a2021-09-01 21:08:30 -05002511 {
Zev Weissca478552024-06-11 23:45:58 +00002512 std::optional<std::string> s =
2513 getMessageValue<std::string>(msg, config.lineName);
2514 if (!s.has_value())
2515 {
2516 return false;
2517 }
Zev Weissa8f116a2021-09-01 21:08:30 -05002518
Zev Weissca478552024-06-11 23:45:58 +00002519 std::smatch m;
2520 value = std::regex_match(s.value(), m, config.matchRegex.value());
2521 }
2522 else
Zev Weissa8f116a2021-09-01 21:08:30 -05002523 {
Zev Weissca478552024-06-11 23:45:58 +00002524 std::optional<bool> v = getMessageValue<bool>(msg, config.lineName);
2525 if (!v.has_value())
2526 {
2527 return false;
2528 }
2529 value = v.value();
Zev Weissa8f116a2021-09-01 21:08:30 -05002530 }
Zev Weissa8f116a2021-09-01 21:08:30 -05002531 return true;
2532 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002533 catch (const std::exception& e)
Zev Weissa8f116a2021-09-01 21:08:30 -05002534 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002535 lg2::error(
2536 "exception while reading dbus property \'{DBUS_NAME}\': {ERROR}",
Zev Weissca478552024-06-11 23:45:58 +00002537 "DBUS_NAME", config.lineName, "ERROR", e);
Zev Weissa8f116a2021-09-01 21:08:30 -05002538 return false;
2539 }
2540}
2541
Patrick Williams439b9c32022-07-22 19:26:53 -05002542static sdbusplus::bus::match_t
Zev Weissa8f116a2021-09-01 21:08:30 -05002543 dbusGPIOMatcher(const ConfigData& cfg, std::function<void(bool)> onMatch)
2544{
Patrick Williamsd394c882023-10-20 11:18:44 -05002545 auto pulseEventMatcherCallback = [&cfg,
2546 onMatch](sdbusplus::message_t& msg) {
Patrick Williams439b9c32022-07-22 19:26:53 -05002547 bool value = false;
Zev Weissca478552024-06-11 23:45:58 +00002548 if (!getDbusMsgGPIOState(msg, cfg, value))
Patrick Williams439b9c32022-07-22 19:26:53 -05002549 {
2550 return;
2551 }
2552 onMatch(value);
2553 };
Zev Weissa8f116a2021-09-01 21:08:30 -05002554
Patrick Williams439b9c32022-07-22 19:26:53 -05002555 return sdbusplus::bus::match_t(
2556 static_cast<sdbusplus::bus_t&>(*conn),
Zev Weissa8f116a2021-09-01 21:08:30 -05002557 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2558 "PropertiesChanged',arg0='" +
Zev Weiss1cc79212024-06-19 22:14:57 +00002559 cfg.interface + "',path='" + cfg.path + "',sender='" +
2560 cfg.dbusName + "'",
Zev Weissa8f116a2021-09-01 21:08:30 -05002561 std::move(pulseEventMatcherCallback));
2562}
2563
Michal Orzeledd211e2022-10-28 13:10:16 +02002564// D-Bus property read functions
2565void reschedulePropertyRead(const ConfigData& configData);
Priyatharshan P70120512020-09-16 18:47:20 +05302566
Michal Orzeledd211e2022-10-28 13:10:16 +02002567int getProperty(const ConfigData& configData)
2568{
2569 std::variant<bool> resp;
2570
2571 try
Priyatharshan P70120512020-09-16 18:47:20 +05302572 {
Michal Orzeledd211e2022-10-28 13:10:16 +02002573 auto method = conn->new_method_call(
2574 configData.dbusName.c_str(), configData.path.c_str(),
2575 "org.freedesktop.DBus.Properties", "Get");
2576 method.append(configData.interface.c_str(),
2577 configData.lineName.c_str());
2578
2579 auto reply = conn->call(method);
2580 if (reply.is_method_error())
2581 {
2582 lg2::error(
2583 "Error reading {PROPERTY} D-Bus property on interface {INTERFACE} and path {PATH}",
2584 "PROPERTY", configData.lineName, "INTERFACE",
2585 configData.interface, "PATH", configData.path);
2586 return -1;
2587 }
2588
2589 reply.read(resp);
2590 }
2591 catch (const sdbusplus::exception_t& e)
2592 {
2593 lg2::error("Exception while reading {PROPERTY}: {WHAT}", "PROPERTY",
2594 configData.lineName, "WHAT", e.what());
2595 reschedulePropertyRead(configData);
Priyatharshan P70120512020-09-16 18:47:20 +05302596 return -1;
2597 }
Michal Orzeledd211e2022-10-28 13:10:16 +02002598
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302599 auto respValue = std::get_if<bool>(&resp);
Priyatharshan P70120512020-09-16 18:47:20 +05302600 if (!respValue)
2601 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002602 lg2::error("Error: {PROPERTY} D-Bus property is not the expected type",
2603 "PROPERTY", configData.lineName);
Priyatharshan P70120512020-09-16 18:47:20 +05302604 return -1;
2605 }
2606 return (*respValue);
2607}
Michal Orzeledd211e2022-10-28 13:10:16 +02002608
2609void setInitialValue(const ConfigData& configData, bool initialValue)
2610{
2611 if (configData.name == "PowerOk")
2612 {
2613 powerState = (initialValue ? PowerState::on : PowerState::off);
2614 hostIface->set_property("CurrentHostState",
2615 std::string(getHostState(powerState)));
2616 }
2617 else if (configData.name == "PowerButton")
2618 {
2619 powerButtonIface->set_property("ButtonPressed", !initialValue);
2620 }
2621 else if (configData.name == "ResetButton")
2622 {
2623 resetButtonIface->set_property("ButtonPressed", !initialValue);
2624 }
2625 else if (configData.name == "NMIButton")
2626 {
2627 nmiButtonIface->set_property("ButtonPressed", !initialValue);
2628 }
2629 else if (configData.name == "IdButton")
2630 {
2631 idButtonIface->set_property("ButtonPressed", !initialValue);
2632 }
2633 else if (configData.name == "PostComplete")
2634 {
2635 OperatingSystemStateStage osState =
2636 (initialValue ? OperatingSystemStateStage::Inactive
2637 : OperatingSystemStateStage::Standby);
2638 setOperatingSystemState(osState);
2639 }
2640 else
2641 {
2642 lg2::error("Unknown name {NAME}", "NAME", configData.name);
2643 }
2644}
2645
2646void reschedulePropertyRead(const ConfigData& configData)
2647{
2648 auto item = dBusRetryTimers.find(configData.name);
2649
2650 if (item == dBusRetryTimers.end())
2651 {
2652 auto newItem = dBusRetryTimers.insert(
2653 {configData.name, boost::asio::steady_timer(io)});
2654
2655 if (!newItem.second)
2656 {
2657 lg2::error("Failed to add new timer for {NAME}", "NAME",
2658 configData.name);
2659 return;
2660 }
2661
2662 item = newItem.first;
2663 }
2664
2665 auto& timer = item->second;
2666 timer.expires_after(
2667 std::chrono::milliseconds(TimerMap["DbusGetPropertyRetry"]));
2668 timer.async_wait([&configData](const boost::system::error_code ec) {
2669 if (ec)
2670 {
2671 lg2::error("Retry timer for {NAME} failed: {MSG}", "NAME",
2672 configData.name, "MSG", ec.message());
2673 dBusRetryTimers.erase(configData.name);
2674 return;
2675 }
2676
2677 int property = getProperty(configData);
2678
2679 if (property >= 0)
2680 {
2681 setInitialValue(configData, (property > 0));
2682 dBusRetryTimers.erase(configData.name);
2683 }
2684 });
2685}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002686} // namespace power_control
2687
2688int main(int argc, char* argv[])
2689{
Lei YU92caa4c2021-02-23 16:59:25 +08002690 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05302691
2692 if (argc > 1)
2693 {
2694 node = argv[1];
2695 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002696 lg2::info("Start Chassis power control service for host : {NODE}", "NODE",
2697 node);
Priyatharshan P70120512020-09-16 18:47:20 +05302698
Lei YU92caa4c2021-02-23 16:59:25 +08002699 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002700
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302701 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08002702 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302703 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002704 lg2::error("Host{NODE}: Error in Parsing...", "NODE", node);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302705 }
Naveen Mosesec972d82021-07-16 21:19:23 +05302706 /* Currently for single host based systems additional busname is added
2707 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
2708 Going forward for single hosts the old bus name without zero numbering
2709 will be removed when all other applications adapted to the
2710 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
2711
2712 if (node == "0")
2713 {
2714 // Request all the dbus names
2715 conn->request_name(hostDbusName.c_str());
2716 conn->request_name(chassisDbusName.c_str());
2717 conn->request_name(osDbusName.c_str());
2718 conn->request_name(buttonDbusName.c_str());
2719 conn->request_name(nmiDbusName.c_str());
2720 conn->request_name(rstCauseDbusName.c_str());
2721 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302722
Zev Weissc4005bd2021-09-01 22:30:23 -05002723 hostDbusName += node;
2724 chassisDbusName += node;
2725 osDbusName += node;
2726 buttonDbusName += node;
2727 nmiDbusName += node;
2728 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002729
Priyatharshan P70120512020-09-16 18:47:20 +05302730 // Request all the dbus names
2731 conn->request_name(hostDbusName.c_str());
2732 conn->request_name(chassisDbusName.c_str());
2733 conn->request_name(osDbusName.c_str());
2734 conn->request_name(buttonDbusName.c_str());
2735 conn->request_name(nmiDbusName.c_str());
2736 conn->request_name(rstCauseDbusName.c_str());
2737
2738 if (sioPwrGoodConfig.lineName.empty() ||
2739 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05302740 {
Lei YU92caa4c2021-02-23 16:59:25 +08002741 sioEnabled = false;
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002742 lg2::info("SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05302743 }
2744
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002745 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302746 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002747 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002748 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302749 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302750 {
2751 return -1;
2752 }
2753 }
Priyatharshan P70120512020-09-16 18:47:20 +05302754 else if (powerOkConfig.type == ConfigType::DBUS)
2755 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002756 static sdbusplus::bus::match_t powerOkEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002757 power_control::dbusGPIOMatcher(powerOkConfig, psPowerOKHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302758 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302759 else
2760 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002761 lg2::error("PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002762 return -1;
2763 }
2764
Lei YU92caa4c2021-02-23 16:59:25 +08002765 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002766 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05302767 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302768 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302769 {
Priyatharshan P70120512020-09-16 18:47:20 +05302770 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002771 sioPowerGoodHandler, sioPowerGoodLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302772 sioPowerGoodEvent))
2773 {
2774 return -1;
2775 }
2776 }
2777 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
2778 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002779 static sdbusplus::bus::match_t sioPwrGoodEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002780 power_control::dbusGPIOMatcher(sioPwrGoodConfig,
2781 sioPowerGoodHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302782 }
2783 else
2784 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002785 lg2::error(
Priyatharshan P70120512020-09-16 18:47:20 +05302786 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302787 return -1;
2788 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002789
Priyatharshan P19c47a32020-08-12 18:16:43 +05302790 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302791 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302792 {
Priyatharshan P70120512020-09-16 18:47:20 +05302793 if (!requestGPIOEvents(sioOnControlConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002794 sioOnControlHandler, sioOnControlLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302795 sioOnControlEvent))
2796 {
2797 return -1;
2798 }
2799 }
2800 else if (sioOnControlConfig.type == ConfigType::DBUS)
2801 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002802 static sdbusplus::bus::match_t sioOnControlEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002803 power_control::dbusGPIOMatcher(sioOnControlConfig,
2804 sioOnControlHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302805 }
2806 else
2807 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002808 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002809 "sioOnControl name should be configured from jsonconfig file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302810 return -1;
2811 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002812
Priyatharshan P19c47a32020-08-12 18:16:43 +05302813 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302814 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302815 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002816 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
Priyatharshan P70120512020-09-16 18:47:20 +05302817 sioS5Line, sioS5Event))
2818 {
2819 return -1;
2820 }
2821 }
2822 else if (sioS5Config.type == ConfigType::DBUS)
2823 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002824 static sdbusplus::bus::match_t sioS5EventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002825 power_control::dbusGPIOMatcher(sioS5Config, sioS5Handler);
Priyatharshan P70120512020-09-16 18:47:20 +05302826 }
2827 else
2828 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002829 lg2::error("sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302830 return -1;
2831 }
2832 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002833
2834 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302835 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002836 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002837 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
2838 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302839 {
2840 return -1;
2841 }
2842 }
Priyatharshan P70120512020-09-16 18:47:20 +05302843 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302844 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002845 static sdbusplus::bus::match_t powerButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002846 power_control::dbusGPIOMatcher(powerButtonConfig,
2847 powerButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002848 }
2849
2850 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302851 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002852 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002853 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
2854 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302855 {
2856 return -1;
2857 }
2858 }
Priyatharshan P70120512020-09-16 18:47:20 +05302859 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302860 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002861 static sdbusplus::bus::match_t resetButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002862 power_control::dbusGPIOMatcher(resetButtonConfig,
2863 resetButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002864 }
2865
2866 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302867 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302868 {
Priyatharshan P70120512020-09-16 18:47:20 +05302869 if (!nmiButtonConfig.lineName.empty())
2870 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002871 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302872 nmiButtonLine, nmiButtonEvent);
2873 }
2874 }
2875 else if (nmiButtonConfig.type == ConfigType::DBUS)
2876 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002877 static sdbusplus::bus::match_t nmiButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002878 power_control::dbusGPIOMatcher(nmiButtonConfig, nmiButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302879 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002880
2881 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302882 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302883 {
Priyatharshan P70120512020-09-16 18:47:20 +05302884 if (!idButtonConfig.lineName.empty())
2885 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002886 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302887 idButtonLine, idButtonEvent);
2888 }
2889 }
2890 else if (idButtonConfig.type == ConfigType::DBUS)
2891 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002892 static sdbusplus::bus::match_t idButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002893 power_control::dbusGPIOMatcher(idButtonConfig, idButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302894 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002895
Jason M. Billsfb957332021-01-28 13:18:46 -08002896#ifdef USE_PLT_RST
Patrick Williams439b9c32022-07-22 19:26:53 -05002897 sdbusplus::bus::match_t pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08002898 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08002899 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2900 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08002901 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08002902#endif
2903
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002904 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302905 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002906 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002907 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
2908 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302909 {
2910 return -1;
2911 }
2912 }
Priyatharshan P70120512020-09-16 18:47:20 +05302913 else if (postCompleteConfig.type == ConfigType::DBUS)
2914 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002915 static sdbusplus::bus::match_t postCompleteEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002916 power_control::dbusGPIOMatcher(postCompleteConfig,
2917 postCompleteHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302918 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302919 else
2920 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002921 lg2::error(
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002922 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002923 return -1;
2924 }
2925
2926 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05302927 if (!nmiOutConfig.lineName.empty())
2928 {
Jian Zhang461a1662022-09-22 11:29:01 +08002929 setGPIOOutput(nmiOutConfig.lineName, !nmiOutConfig.polarity,
2930 nmiOutLine);
Priyatharshan P70120512020-09-16 18:47:20 +05302931 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002932
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002933 // Initialize POWER_OUT and RESET_OUT GPIO.
2934 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05302935 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002936 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002937 if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
2938 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302939 {
2940 return -1;
2941 }
2942 }
2943 else
2944 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002945 lg2::error("powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002946 return -1;
2947 }
2948
Priyatharshan P70120512020-09-16 18:47:20 +05302949 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002950 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002951 if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
2952 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302953 {
2954 return -1;
2955 }
2956 }
2957 else
2958 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002959 lg2::error("ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002960 return -1;
2961 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002962 // Release line
2963 line.reset();
2964
Matt Simmering58e379d2022-09-23 14:45:50 -07002965 // Initialize the power state and operating system state
Lei YU92caa4c2021-02-23 16:59:25 +08002966 powerState = PowerState::off;
Matt Simmering58e379d2022-09-23 14:45:50 -07002967 operatingSystemState = OperatingSystemStateStage::Inactive;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002968 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05302969
2970 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002971 {
Jean-Marie Verdun61b4a5b2021-09-19 08:53:28 -04002972 if (psPowerOKLine.get_value() > 0 ||
Lei YUa37c2472021-09-26 15:57:12 +08002973 (sioEnabled &&
2974 (sioPowerGoodLine.get_value() == sioPwrGoodConfig.polarity)))
Priyatharshan P70120512020-09-16 18:47:20 +05302975 {
2976 powerState = PowerState::on;
2977 }
2978 }
2979 else
2980 {
2981 if (getProperty(powerOkConfig))
2982 {
2983 powerState = PowerState::on;
2984 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002985 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002986 // Check if we need to start the Power Restore policy
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03002987 if (powerState != PowerState::on)
2988 {
2989 powerRestore.run();
2990 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002991
Lei YU92caa4c2021-02-23 16:59:25 +08002992 if (nmiOutLine)
2993 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002994
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002995 lg2::info("Initializing power state.");
Lei YU92caa4c2021-02-23 16:59:25 +08002996 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002997
2998 // Power Control Service
2999 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003000 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003001
3002 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303003 hostIface =
3004 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
3005 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003006 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08003007 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003008 "RequestedHostTransition",
3009 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
3010 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003011 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
3012 {
3013 // if power button is masked, ignore this
3014 if (!powerButtonMask)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003015 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003016 sendPowerControlEvent(Event::gracefulPowerOffRequest);
3017 addRestartCause(RestartCause::command);
Jason M. Billse7520ba2020-01-31 11:19:03 -08003018 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003019 else
3020 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003021 lg2::info("Power Button Masked.");
3022 throw std::invalid_argument("Transition Request Masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003023 return 0;
3024 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003025 }
3026 else if (requested == "xyz.openbmc_project.State.Host.Transition.On")
3027 {
3028 // if power button is masked, ignore this
3029 if (!powerButtonMask)
3030 {
3031 sendPowerControlEvent(Event::powerOnRequest);
3032 addRestartCause(RestartCause::command);
3033 }
3034 else
3035 {
3036 lg2::info("Power Button Masked.");
3037 throw std::invalid_argument("Transition Request Masked");
3038 return 0;
3039 }
3040 }
3041 else if (requested ==
3042 "xyz.openbmc_project.State.Host.Transition.Reboot")
3043 {
3044 // if power button is masked, ignore this
3045 if (!powerButtonMask)
3046 {
3047 sendPowerControlEvent(Event::powerCycleRequest);
3048 addRestartCause(RestartCause::command);
3049 }
3050 else
3051 {
3052 lg2::info("Power Button Masked.");
3053 throw std::invalid_argument("Transition Request Masked");
3054 return 0;
3055 }
3056 }
3057 else if (requested ==
3058 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot")
3059 {
3060 // if reset button is masked, ignore this
3061 if (!resetButtonMask)
3062 {
3063 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
3064 addRestartCause(RestartCause::command);
3065 }
3066 else
3067 {
3068 lg2::info("Reset Button Masked.");
3069 throw std::invalid_argument("Transition Request Masked");
3070 return 0;
3071 }
3072 }
3073 else if (requested ==
3074 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot")
3075 {
3076 // if reset button is masked, ignore this
3077 if (!resetButtonMask)
3078 {
3079 sendPowerControlEvent(Event::resetRequest);
3080 addRestartCause(RestartCause::command);
3081 }
3082 else
3083 {
3084 lg2::info("Reset Button Masked.");
3085 throw std::invalid_argument("Transition Request Masked");
3086 return 0;
3087 }
3088 }
3089 else
3090 {
3091 lg2::error("Unrecognized host state transition request.");
3092 throw std::invalid_argument("Unrecognized Transition Request");
3093 return 0;
3094 }
3095 resp = requested;
3096 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003097 });
Lei YU92caa4c2021-02-23 16:59:25 +08003098 hostIface->register_property("CurrentHostState",
3099 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003100
Lei YU92caa4c2021-02-23 16:59:25 +08003101 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003102
3103 // Chassis Control Service
3104 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003105 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003106
3107 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003108 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05303109 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003110 "xyz.openbmc_project.State.Chassis");
3111
Lei YU92caa4c2021-02-23 16:59:25 +08003112 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003113 "RequestedPowerTransition",
3114 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
3115 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003116 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
3117 {
3118 // if power button is masked, ignore this
3119 if (!powerButtonMask)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003120 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003121 sendPowerControlEvent(Event::powerOffRequest);
3122 addRestartCause(RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003123 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003124 else
3125 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003126 lg2::info("Power Button Masked.");
3127 throw std::invalid_argument("Transition Request Masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003128 return 0;
3129 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003130 }
3131 else if (requested == "xyz.openbmc_project.State.Chassis.Transition.On")
3132 {
3133 // if power button is masked, ignore this
3134 if (!powerButtonMask)
3135 {
3136 sendPowerControlEvent(Event::powerOnRequest);
3137 addRestartCause(RestartCause::command);
3138 }
3139 else
3140 {
3141 lg2::info("Power Button Masked.");
3142 throw std::invalid_argument("Transition Request Masked");
3143 return 0;
3144 }
3145 }
3146 else if (requested ==
3147 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3148 {
3149 // if power button is masked, ignore this
3150 if (!powerButtonMask)
3151 {
3152 sendPowerControlEvent(Event::powerCycleRequest);
3153 addRestartCause(RestartCause::command);
3154 }
3155 else
3156 {
3157 lg2::info("Power Button Masked.");
3158 throw std::invalid_argument("Transition Request Masked");
3159 return 0;
3160 }
3161 }
3162 else
3163 {
3164 lg2::error("Unrecognized chassis state transition request.");
3165 throw std::invalid_argument("Unrecognized Transition Request");
3166 return 0;
3167 }
3168 resp = requested;
3169 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003170 });
Lei YU92caa4c2021-02-23 16:59:25 +08003171 chassisIface->register_property("CurrentPowerState",
3172 std::string(getChassisState(powerState)));
3173 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003174
Lei YU92caa4c2021-02-23 16:59:25 +08003175 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003176
Vijay Khemka04175c22020-10-09 14:28:11 -07003177#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003178 // Chassis System Service
3179 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003180 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003181
3182 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003183 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003184 "/xyz/openbmc_project/state/chassis_system0",
3185 "xyz.openbmc_project.State.Chassis");
3186
Lei YU92caa4c2021-02-23 16:59:25 +08003187 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003188 "RequestedPowerTransition",
3189 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3190 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003191 if (requested ==
3192 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3193 {
3194 systemReset();
3195 addRestartCause(RestartCause::command);
3196 }
3197 else
3198 {
3199 lg2::error("Unrecognized chassis system state transition request.");
3200 throw std::invalid_argument("Unrecognized Transition Request");
3201 return 0;
3202 }
3203 resp = requested;
3204 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003205 });
Lei YU92caa4c2021-02-23 16:59:25 +08003206 chassisSysIface->register_property(
3207 "CurrentPowerState", std::string(getChassisState(powerState)));
3208 chassisSysIface->register_property("LastStateChangeTime",
3209 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003210
Lei YU92caa4c2021-02-23 16:59:25 +08003211 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003212
Naveen Moses117c34e2021-05-26 20:10:51 +05303213 if (!slotPowerConfig.lineName.empty())
3214 {
3215 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3216 {
3217 return -1;
3218 }
3219
3220 slotPowerState = SlotPowerState::off;
3221 if (slotPowerLine.get_value() > 0)
3222 {
3223 slotPowerState = SlotPowerState::on;
3224 }
3225
3226 chassisSlotIface = chassisSysServer.add_interface(
3227 "/xyz/openbmc_project/state/chassis_system" + node,
3228 "xyz.openbmc_project.State.Chassis");
3229 chassisSlotIface->register_property(
3230 "RequestedPowerTransition",
3231 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3232 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003233 if (requested == "xyz.openbmc_project.State.Chassis.Transition.On")
3234 {
3235 slotPowerOn();
3236 }
3237 else if (requested ==
3238 "xyz.openbmc_project.State.Chassis.Transition.Off")
3239 {
3240 slotPowerOff();
3241 }
3242 else if (requested ==
3243 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3244 {
3245 slotPowerCycle();
3246 }
3247 else
3248 {
3249 lg2::error(
3250 "Unrecognized chassis system state transition request.\n");
3251 throw std::invalid_argument("Unrecognized Transition Request");
3252 return 0;
3253 }
3254 resp = requested;
3255 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003256 });
Naveen Moses117c34e2021-05-26 20:10:51 +05303257 chassisSlotIface->register_property(
3258 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3259 chassisSlotIface->register_property("LastStateChangeTime",
3260 getCurrentTimeMs());
3261 chassisSlotIface->initialize();
3262 }
3263#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003264 // Buttons Service
3265 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003266 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003267
Priyatharshan P70120512020-09-16 18:47:20 +05303268 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003269 {
Priyatharshan P70120512020-09-16 18:47:20 +05303270 // Power Button Interface
3271 power_control::powerButtonIface = buttonsServer.add_interface(
3272 "/xyz/openbmc_project/chassis/buttons/power",
3273 "xyz.openbmc_project.Chassis.Buttons");
3274
3275 powerButtonIface->register_property(
Patrick Williamsd394c882023-10-20 11:18:44 -05003276 "ButtonMasked", false, [](const bool requested, bool& current) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003277 if (requested)
3278 {
3279 if (powerButtonMask)
Priyatharshan P70120512020-09-16 18:47:20 +05303280 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003281 return 1;
Priyatharshan P70120512020-09-16 18:47:20 +05303282 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003283 if (!setGPIOOutput(powerOutConfig.lineName,
3284 !powerOutConfig.polarity, powerButtonMask))
Priyatharshan P70120512020-09-16 18:47:20 +05303285 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003286 throw std::runtime_error("Failed to request GPIO");
3287 return 0;
Priyatharshan P70120512020-09-16 18:47:20 +05303288 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003289 lg2::info("Power Button Masked.");
3290 }
3291 else
3292 {
3293 if (!powerButtonMask)
3294 {
3295 return 1;
3296 }
3297 lg2::info("Power Button Un-masked");
3298 powerButtonMask.reset();
3299 }
3300 // Update the mask setting
3301 current = requested;
3302 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003303 });
Priyatharshan P70120512020-09-16 18:47:20 +05303304
3305 // Check power button state
3306 bool powerButtonPressed;
3307 if (powerButtonConfig.type == ConfigType::GPIO)
3308 {
3309 powerButtonPressed = powerButtonLine.get_value() == 0;
3310 }
3311 else
3312 {
3313 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3314 }
3315
3316 powerButtonIface->register_property("ButtonPressed",
3317 powerButtonPressed);
3318
3319 powerButtonIface->initialize();
3320 }
3321
3322 if (!resetButtonConfig.lineName.empty())
3323 {
3324 // Reset Button Interface
3325
Lei YU92caa4c2021-02-23 16:59:25 +08003326 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003327 "/xyz/openbmc_project/chassis/buttons/reset",
3328 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003329
Lei YU92caa4c2021-02-23 16:59:25 +08003330 resetButtonIface->register_property(
Patrick Williamsd394c882023-10-20 11:18:44 -05003331 "ButtonMasked", false, [](const bool requested, bool& current) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003332 if (requested)
3333 {
3334 if (resetButtonMask)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003335 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003336 return 1;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003337 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003338 if (!setGPIOOutput(resetOutConfig.lineName,
3339 !resetOutConfig.polarity, resetButtonMask))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003340 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003341 throw std::runtime_error("Failed to request GPIO");
3342 return 0;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003343 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003344 lg2::info("Reset Button Masked.");
3345 }
3346 else
3347 {
3348 if (!resetButtonMask)
3349 {
3350 return 1;
3351 }
3352 lg2::info("Reset Button Un-masked");
3353 resetButtonMask.reset();
3354 }
3355 // Update the mask setting
3356 current = requested;
3357 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003358 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003359
John Wang6c090072020-09-30 13:32:16 +08003360 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303361 bool resetButtonPressed;
3362 if (resetButtonConfig.type == ConfigType::GPIO)
3363 {
3364 resetButtonPressed = resetButtonLine.get_value() == 0;
3365 }
3366 else
3367 {
3368 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3369 }
3370
Lei YU92caa4c2021-02-23 16:59:25 +08003371 resetButtonIface->register_property("ButtonPressed",
3372 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003373
Lei YU92caa4c2021-02-23 16:59:25 +08003374 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003375 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003376
Lei YU92caa4c2021-02-23 16:59:25 +08003377 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003378 {
3379 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003380 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003381 "/xyz/openbmc_project/chassis/buttons/nmi",
3382 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003383
Lei YU92caa4c2021-02-23 16:59:25 +08003384 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003385 "ButtonMasked", false, [](const bool requested, bool& current) {
Patrick Williamsd394c882023-10-20 11:18:44 -05003386 if (nmiButtonMasked == requested)
3387 {
3388 // NMI button mask is already set as requested, so no change
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003389 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003390 }
3391 if (requested)
3392 {
3393 lg2::info("NMI Button Masked.");
3394 nmiButtonMasked = true;
3395 }
3396 else
3397 {
3398 lg2::info("NMI Button Un-masked.");
3399 nmiButtonMasked = false;
3400 }
3401 // Update the mask setting
3402 current = nmiButtonMasked;
3403 return 1;
3404 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003405
Vijay Khemka33a532d2019-11-14 16:50:35 -08003406 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303407 bool nmiButtonPressed;
3408 if (nmiButtonConfig.type == ConfigType::GPIO)
3409 {
3410 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3411 }
3412 else
3413 {
3414 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3415 }
3416
Lei YU92caa4c2021-02-23 16:59:25 +08003417 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003418
Lei YU92caa4c2021-02-23 16:59:25 +08003419 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003420 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003421
Lei YU92caa4c2021-02-23 16:59:25 +08003422 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003423 {
3424 // NMI out Service
3425 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003426 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003427
Vijay Khemka33a532d2019-11-14 16:50:35 -08003428 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303429 nmiOutIface = nmiOutServer.add_interface(
3430 "/xyz/openbmc_project/control/host" + node + "/nmi",
3431 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003432 nmiOutIface->register_method("NMI", nmiReset);
3433 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003434 }
Chen Yugang174ec662019-08-19 19:58:49 +08003435
Lei YU92caa4c2021-02-23 16:59:25 +08003436 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003437 {
3438 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003439 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003440 "/xyz/openbmc_project/chassis/buttons/id",
3441 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003442
Vijay Khemka33a532d2019-11-14 16:50:35 -08003443 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303444 bool idButtonPressed;
3445 if (idButtonConfig.type == ConfigType::GPIO)
3446 {
3447 idButtonPressed = idButtonLine.get_value() == 0;
3448 }
3449 else
3450 {
3451 idButtonPressed = getProperty(idButtonConfig) == 0;
3452 }
3453
Lei YU92caa4c2021-02-23 16:59:25 +08003454 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003455
Lei YU92caa4c2021-02-23 16:59:25 +08003456 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003457 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003458
3459 // OS State Service
3460 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003461 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003462
3463 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003464 osIface = osServer.add_interface(
Potin Lai33737912024-02-23 09:53:47 +08003465 "/xyz/openbmc_project/state/host" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003466 "xyz.openbmc_project.State.OperatingSystem.Status");
3467
3468 // Get the initial OS state based on POST complete
3469 // 0: Asserted, OS state is "Standby" (ready to boot)
3470 // 1: De-Asserted, OS state is "Inactive"
Tim Lee86239182021-12-23 11:46:01 +08003471 OperatingSystemStateStage osState;
Priyatharshan P70120512020-09-16 18:47:20 +05303472 if (postCompleteConfig.type == ConfigType::GPIO)
3473 {
Tim Lee86239182021-12-23 11:46:01 +08003474 osState = postCompleteLine.get_value() > 0
3475 ? OperatingSystemStateStage::Inactive
3476 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303477 }
3478 else
3479 {
Tim Lee86239182021-12-23 11:46:01 +08003480 osState = getProperty(postCompleteConfig) > 0
3481 ? OperatingSystemStateStage::Inactive
3482 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303483 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003484
Tim Lee86239182021-12-23 11:46:01 +08003485 osIface->register_property(
3486 "OperatingSystemState",
3487 std::string(getOperatingSystemStateStage(osState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003488
Lei YU92caa4c2021-02-23 16:59:25 +08003489 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003490
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003491 // Restart Cause Service
3492 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003493 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003494
3495 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003496 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303497 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003498 "xyz.openbmc_project.Control.Host.RestartCause");
3499
Lei YU92caa4c2021-02-23 16:59:25 +08003500 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003501 "RestartCause",
3502 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3503
Lei YU92caa4c2021-02-23 16:59:25 +08003504 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003505 "RequestedRestartCause",
3506 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3507 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003508 if (requested ==
3509 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3510 {
3511 addRestartCause(RestartCause::watchdog);
3512 }
3513 else
3514 {
3515 throw std::invalid_argument("Unrecognized RestartCause Request");
3516 return 0;
3517 }
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003518
Patrick Williams48aa1f02023-05-10 07:50:30 -05003519 lg2::info("RestartCause requested: {RESTART_CAUSE}", "RESTART_CAUSE",
3520 requested);
3521 resp = requested;
3522 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003523 });
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003524
Lei YU92caa4c2021-02-23 16:59:25 +08003525 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003526
Lei YU92caa4c2021-02-23 16:59:25 +08003527 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003528
Konstantin Aladyshevcfc4d252021-11-18 11:08:38 +03003529 if (!hpmStbyEnConfig.lineName.empty())
3530 {
3531 // Set to indicate BMC's power control module is ready to take
3532 // the inputs [PWR_GOOD] from the HPM FPGA
3533 gpiod::line hpmLine;
3534 if (!setGPIOOutput(hpmStbyEnConfig.lineName, hpmStbyEnConfig.polarity,
3535 hpmLine))
3536 {
3537 return -1;
3538 }
3539 }
3540
Lei YU92caa4c2021-02-23 16:59:25 +08003541 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003542
3543 return 0;
3544}