blob: a4ef0787ad4f4ea17f733ad9c1e5e5ea0cd0cd27 [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>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070033#include <string_view>
34
35namespace power_control
36{
Ed Tanous744e9a92023-02-28 13:35:22 -080037static boost::asio::io_context io;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070038std::shared_ptr<sdbusplus::asio::connection> conn;
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +030039PersistentState appState;
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +030040PowerRestoreController powerRestore(io);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053041
42static std::string node = "0";
Andrei Kartashev3efcf372021-12-29 15:32:17 +030043static const std::string appName = "power-control";
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053044
Priyatharshan P70120512020-09-16 18:47:20 +053045enum class DbusConfigType
46{
47 name = 1,
48 path,
49 interface,
50 property
51};
52boost::container::flat_map<DbusConfigType, std::string> dbusParams = {
53 {DbusConfigType::name, "DbusName"},
54 {DbusConfigType::path, "Path"},
55 {DbusConfigType::interface, "Interface"},
56 {DbusConfigType::property, "Property"}};
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053057
Priyatharshan P70120512020-09-16 18:47:20 +053058enum class ConfigType
59{
60 GPIO = 1,
61 DBUS
62};
63
64struct ConfigData
65{
66 std::string name;
67 std::string lineName;
68 std::string dbusName;
69 std::string path;
70 std::string interface;
Jean-Marie Verdun50937e72021-08-31 09:15:49 -070071 bool polarity;
Priyatharshan P70120512020-09-16 18:47:20 +053072 ConfigType type;
73};
74
75static ConfigData powerOutConfig;
76static ConfigData powerOkConfig;
77static ConfigData resetOutConfig;
78static ConfigData nmiOutConfig;
79static ConfigData sioPwrGoodConfig;
80static ConfigData sioOnControlConfig;
81static ConfigData sioS5Config;
82static ConfigData postCompleteConfig;
83static ConfigData powerButtonConfig;
84static ConfigData resetButtonConfig;
85static ConfigData idButtonConfig;
86static ConfigData nmiButtonConfig;
Naveen Moses117c34e2021-05-26 20:10:51 +053087static ConfigData slotPowerConfig;
Konstantin Aladyshevcfc4d252021-11-18 11:08:38 +030088static ConfigData hpmStbyEnConfig;
Naveen Moses117c34e2021-05-26 20:10:51 +053089
Priyatharshan P70120512020-09-16 18:47:20 +053090// map for storing list of gpio parameters whose config are to be read from x86
91// power control json config
92boost::container::flat_map<std::string, ConfigData*> powerSignalMap = {
93 {"PowerOut", &powerOutConfig},
94 {"PowerOk", &powerOkConfig},
95 {"ResetOut", &resetOutConfig},
96 {"NMIOut", &nmiOutConfig},
97 {"SioPowerGood", &sioPwrGoodConfig},
98 {"SioOnControl", &sioOnControlConfig},
99 {"SIOS5", &sioS5Config},
100 {"PostComplete", &postCompleteConfig},
101 {"PowerButton", &powerButtonConfig},
102 {"ResetButton", &resetButtonConfig},
103 {"IdButton", &idButtonConfig},
Naveen Moses117c34e2021-05-26 20:10:51 +0530104 {"NMIButton", &nmiButtonConfig},
Konstantin Aladyshevcfc4d252021-11-18 11:08:38 +0300105 {"SlotPower", &slotPowerConfig},
106 {"HpmStbyEn", &hpmStbyEnConfig}};
Priyatharshan P70120512020-09-16 18:47:20 +0530107
108static std::string hostDbusName = "xyz.openbmc_project.State.Host";
109static std::string chassisDbusName = "xyz.openbmc_project.State.Chassis";
110static std::string osDbusName = "xyz.openbmc_project.State.OperatingSystem";
111static std::string buttonDbusName = "xyz.openbmc_project.Chassis.Buttons";
112static std::string nmiDbusName = "xyz.openbmc_project.Control.Host.NMI";
113static std::string rstCauseDbusName =
114 "xyz.openbmc_project.Control.Host.RestartCause";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700115static std::shared_ptr<sdbusplus::asio::dbus_interface> hostIface;
116static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700117#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -0700118static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSysIface;
Naveen Moses117c34e2021-05-26 20:10:51 +0530119static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSlotIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700120#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700121static std::shared_ptr<sdbusplus::asio::dbus_interface> powerButtonIface;
122static std::shared_ptr<sdbusplus::asio::dbus_interface> resetButtonIface;
123static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiButtonIface;
124static std::shared_ptr<sdbusplus::asio::dbus_interface> osIface;
125static std::shared_ptr<sdbusplus::asio::dbus_interface> idButtonIface;
Chen Yugang174ec662019-08-19 19:58:49 +0800126static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiOutIface;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700127static std::shared_ptr<sdbusplus::asio::dbus_interface> restartCauseIface;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700128
129static gpiod::line powerButtonMask;
130static gpiod::line resetButtonMask;
131static bool nmiButtonMasked = false;
Matt Simmering58e379d2022-09-23 14:45:50 -0700132#if IGNORE_SOFT_RESETS_DURING_POST
133static bool ignoreNextSoftReset = false;
134#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700135
Priyatharshan P70120512020-09-16 18:47:20 +0530136// This map contains all timer values that are to be read from json config
137boost::container::flat_map<std::string, int> TimerMap = {
Jason M. Billsaeefe042021-09-08 14:56:11 -0700138 {"PowerPulseMs", 200},
139 {"ForceOffPulseMs", 15000},
140 {"ResetPulseMs", 500},
141 {"PowerCycleMs", 5000},
142 {"SioPowerGoodWatchdogMs", 1000},
143 {"PsPowerOKWatchdogMs", 8000},
144 {"GracefulPowerOffS", (5 * 60)},
145 {"WarmResetCheckMs", 500},
146 {"PowerOffSaveMs", 7000},
Michal Orzeledd211e2022-10-28 13:10:16 +0200147 {"SlotPowerCycleMs", 200},
148 {"DbusGetPropertyRetry", 1000}};
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700149
150static bool nmiEnabled = true;
Olivier FAURAXd7ea2832023-04-14 14:08:02 +0000151static bool nmiWhenPoweredOff = true;
Priyatharshan P19c47a32020-08-12 18:16:43 +0530152static bool sioEnabled = true;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700153
154// Timers
155// Time holding GPIOs asserted
156static boost::asio::steady_timer gpioAssertTimer(io);
157// Time between off and on during a power cycle
158static boost::asio::steady_timer powerCycleTimer(io);
159// Time OS gracefully powering off
160static boost::asio::steady_timer gracefulPowerOffTimer(io);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700161// Time the warm reset check
162static boost::asio::steady_timer warmResetCheckTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700163// Time power supply power OK assertion on power-on
164static boost::asio::steady_timer psPowerOKWatchdogTimer(io);
165// Time SIO power good assertion on power-on
166static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io);
167// Time power-off state save for power loss tracking
168static boost::asio::steady_timer powerStateSaveTimer(io);
169// POH timer
170static boost::asio::steady_timer pohCounterTimer(io);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700171// Time when to allow restart cause updates
172static boost::asio::steady_timer restartCauseTimer(io);
Naveen Moses117c34e2021-05-26 20:10:51 +0530173static boost::asio::steady_timer slotPowerCycleTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700174
Michal Orzeledd211e2022-10-28 13:10:16 +0200175// Map containing timers used for D-Bus get-property retries
176static boost::container::flat_map<std::string, boost::asio::steady_timer>
177 dBusRetryTimers;
178
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700179// GPIO Lines and Event Descriptors
180static gpiod::line psPowerOKLine;
181static boost::asio::posix::stream_descriptor psPowerOKEvent(io);
182static gpiod::line sioPowerGoodLine;
183static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io);
184static gpiod::line sioOnControlLine;
185static boost::asio::posix::stream_descriptor sioOnControlEvent(io);
186static gpiod::line sioS5Line;
187static boost::asio::posix::stream_descriptor sioS5Event(io);
188static gpiod::line powerButtonLine;
189static boost::asio::posix::stream_descriptor powerButtonEvent(io);
190static gpiod::line resetButtonLine;
191static boost::asio::posix::stream_descriptor resetButtonEvent(io);
192static gpiod::line nmiButtonLine;
193static boost::asio::posix::stream_descriptor nmiButtonEvent(io);
194static gpiod::line idButtonLine;
195static boost::asio::posix::stream_descriptor idButtonEvent(io);
196static gpiod::line postCompleteLine;
197static boost::asio::posix::stream_descriptor postCompleteEvent(io);
198static gpiod::line nmiOutLine;
Naveen Moses117c34e2021-05-26 20:10:51 +0530199static gpiod::line slotPowerLine;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700200
201static constexpr uint8_t beepPowerFail = 8;
202
203static void beep(const uint8_t& beepPriority)
204{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800205 lg2::info("Beep with priority: {BEEP_PRIORITY}", "BEEP_PRIORITY",
206 beepPriority);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700207
208 conn->async_method_call(
209 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -0500210 if (ec)
211 {
212 lg2::error(
213 "beep returned error with async_method_call (ec = {ERROR_MSG})",
214 "ERROR_MSG", ec.message());
215 return;
216 }
Patrick Williamsd394c882023-10-20 11:18:44 -0500217 },
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700218 "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
219 "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
220}
221
Tim Lee86239182021-12-23 11:46:01 +0800222enum class OperatingSystemStateStage
223{
224 Inactive,
225 Standby,
226};
Matt Simmering58e379d2022-09-23 14:45:50 -0700227static OperatingSystemStateStage operatingSystemState;
Tim Lee86239182021-12-23 11:46:01 +0800228static constexpr std::string_view
229 getOperatingSystemStateStage(const OperatingSystemStateStage stage)
230{
231 switch (stage)
232 {
233 case OperatingSystemStateStage::Inactive:
234 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
235 break;
236 case OperatingSystemStateStage::Standby:
237 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Standby";
238 break;
239 default:
240 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
241 break;
242 }
243};
244static void setOperatingSystemState(const OperatingSystemStateStage stage)
245{
Matt Simmering58e379d2022-09-23 14:45:50 -0700246 operatingSystemState = stage;
247#if IGNORE_SOFT_RESETS_DURING_POST
248 // If POST complete has asserted set ignoreNextSoftReset to false to avoid
249 // masking soft resets after POST
250 if (operatingSystemState == OperatingSystemStateStage::Standby)
251 {
252 ignoreNextSoftReset = false;
253 }
254#endif
Tim Lee86239182021-12-23 11:46:01 +0800255 osIface->set_property("OperatingSystemState",
256 std::string(getOperatingSystemStateStage(stage)));
257
258 lg2::info("Moving os state to {STATE} stage", "STATE",
259 getOperatingSystemStateStage(stage));
260}
261
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700262enum class PowerState
263{
264 on,
265 waitForPSPowerOK,
266 waitForSIOPowerGood,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700267 off,
268 transitionToOff,
269 gracefulTransitionToOff,
270 cycleOff,
271 transitionToCycleOff,
272 gracefulTransitionToCycleOff,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700273 checkForWarmReset,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700274};
275static PowerState powerState;
276static std::string getPowerStateName(PowerState state)
277{
278 switch (state)
279 {
280 case PowerState::on:
281 return "On";
282 break;
283 case PowerState::waitForPSPowerOK:
284 return "Wait for Power Supply Power OK";
285 break;
286 case PowerState::waitForSIOPowerGood:
287 return "Wait for SIO Power Good";
288 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700289 case PowerState::off:
290 return "Off";
291 break;
292 case PowerState::transitionToOff:
293 return "Transition to Off";
294 break;
295 case PowerState::gracefulTransitionToOff:
296 return "Graceful Transition to Off";
297 break;
298 case PowerState::cycleOff:
299 return "Power Cycle Off";
300 break;
301 case PowerState::transitionToCycleOff:
302 return "Transition to Power Cycle Off";
303 break;
304 case PowerState::gracefulTransitionToCycleOff:
305 return "Graceful Transition to Power Cycle Off";
306 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700307 case PowerState::checkForWarmReset:
308 return "Check for Warm Reset";
309 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700310 default:
311 return "unknown state: " + std::to_string(static_cast<int>(state));
312 break;
313 }
314}
315static void logStateTransition(const PowerState state)
316{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800317 lg2::info("Host{HOST}: Moving to \"{STATE}\" state", "HOST", node, "STATE",
318 getPowerStateName(state));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700319}
320
321enum class Event
322{
323 psPowerOKAssert,
324 psPowerOKDeAssert,
325 sioPowerGoodAssert,
326 sioPowerGoodDeAssert,
327 sioS5Assert,
328 sioS5DeAssert,
Jason M. Billsfb957332021-01-28 13:18:46 -0800329 pltRstAssert,
330 pltRstDeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700331 postCompleteAssert,
332 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700333 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700334 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700335 powerCycleTimerExpired,
336 psPowerOKWatchdogTimerExpired,
337 sioPowerGoodWatchdogTimerExpired,
338 gracefulPowerOffTimerExpired,
339 powerOnRequest,
340 powerOffRequest,
341 powerCycleRequest,
342 resetRequest,
343 gracefulPowerOffRequest,
344 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700345 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700346};
347static std::string getEventName(Event event)
348{
349 switch (event)
350 {
351 case Event::psPowerOKAssert:
352 return "power supply power OK assert";
353 break;
354 case Event::psPowerOKDeAssert:
355 return "power supply power OK de-assert";
356 break;
357 case Event::sioPowerGoodAssert:
358 return "SIO power good assert";
359 break;
360 case Event::sioPowerGoodDeAssert:
361 return "SIO power good de-assert";
362 break;
363 case Event::sioS5Assert:
364 return "SIO S5 assert";
365 break;
366 case Event::sioS5DeAssert:
367 return "SIO S5 de-assert";
368 break;
Jason M. Billsfb957332021-01-28 13:18:46 -0800369 case Event::pltRstAssert:
370 return "PLT_RST assert";
371 break;
372 case Event::pltRstDeAssert:
373 return "PLT_RST de-assert";
374 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700375 case Event::postCompleteAssert:
376 return "POST Complete assert";
377 break;
378 case Event::postCompleteDeAssert:
379 return "POST Complete de-assert";
380 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700381 case Event::powerButtonPressed:
382 return "power button pressed";
383 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700384 case Event::resetButtonPressed:
385 return "reset button pressed";
386 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700387 case Event::powerCycleTimerExpired:
388 return "power cycle timer expired";
389 break;
390 case Event::psPowerOKWatchdogTimerExpired:
391 return "power supply power OK watchdog timer expired";
392 break;
393 case Event::sioPowerGoodWatchdogTimerExpired:
394 return "SIO power good watchdog timer expired";
395 break;
396 case Event::gracefulPowerOffTimerExpired:
397 return "graceful power-off timer expired";
398 break;
399 case Event::powerOnRequest:
400 return "power-on request";
401 break;
402 case Event::powerOffRequest:
403 return "power-off request";
404 break;
405 case Event::powerCycleRequest:
406 return "power-cycle request";
407 break;
408 case Event::resetRequest:
409 return "reset request";
410 break;
411 case Event::gracefulPowerOffRequest:
412 return "graceful power-off request";
413 break;
414 case Event::gracefulPowerCycleRequest:
415 return "graceful power-cycle request";
416 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700417 case Event::warmResetDetected:
418 return "warm reset detected";
419 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700420 default:
421 return "unknown event: " + std::to_string(static_cast<int>(event));
422 break;
423 }
424}
425static void logEvent(const std::string_view stateHandler, const Event event)
426{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800427 lg2::info("{STATE_HANDLER}: {EVENT} event received", "STATE_HANDLER",
428 stateHandler, "EVENT", getEventName(event));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700429}
430
431// Power state handlers
432static void powerStateOn(const Event event);
433static void powerStateWaitForPSPowerOK(const Event event);
434static void powerStateWaitForSIOPowerGood(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700435static void powerStateOff(const Event event);
436static void powerStateTransitionToOff(const Event event);
437static void powerStateGracefulTransitionToOff(const Event event);
438static void powerStateCycleOff(const Event event);
439static void powerStateTransitionToCycleOff(const Event event);
440static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700441static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700442
443static std::function<void(const Event)> getPowerStateHandler(PowerState state)
444{
445 switch (state)
446 {
447 case PowerState::on:
448 return powerStateOn;
449 break;
450 case PowerState::waitForPSPowerOK:
451 return powerStateWaitForPSPowerOK;
452 break;
453 case PowerState::waitForSIOPowerGood:
454 return powerStateWaitForSIOPowerGood;
455 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700456 case PowerState::off:
457 return powerStateOff;
458 break;
459 case PowerState::transitionToOff:
460 return powerStateTransitionToOff;
461 break;
462 case PowerState::gracefulTransitionToOff:
463 return powerStateGracefulTransitionToOff;
464 break;
465 case PowerState::cycleOff:
466 return powerStateCycleOff;
467 break;
468 case PowerState::transitionToCycleOff:
469 return powerStateTransitionToCycleOff;
470 break;
471 case PowerState::gracefulTransitionToCycleOff:
472 return powerStateGracefulTransitionToCycleOff;
473 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700474 case PowerState::checkForWarmReset:
475 return powerStateCheckForWarmReset;
476 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700477 default:
Zev Weiss047bcb52020-08-20 21:28:11 +0000478 return nullptr;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700479 break;
480 }
481};
482
483static void sendPowerControlEvent(const Event event)
484{
485 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
486 if (handler == nullptr)
487 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800488 lg2::error("Failed to find handler for power state: {STATE}", "STATE",
489 static_cast<int>(powerState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700490 return;
491 }
492 handler(event);
493}
494
495static uint64_t getCurrentTimeMs()
496{
497 struct timespec time = {};
498
499 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
500 {
501 return 0;
502 }
503 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
504 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
505
506 return currentTimeMs;
507}
508
509static constexpr std::string_view getHostState(const PowerState state)
510{
511 switch (state)
512 {
513 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700514 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700515 case PowerState::gracefulTransitionToCycleOff:
516 return "xyz.openbmc_project.State.Host.HostState.Running";
517 break;
518 case PowerState::waitForPSPowerOK:
519 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700520 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700521 case PowerState::transitionToOff:
522 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700523 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700524 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700525 return "xyz.openbmc_project.State.Host.HostState.Off";
526 break;
527 default:
528 return "";
529 break;
530 }
531};
532static constexpr std::string_view getChassisState(const PowerState state)
533{
534 switch (state)
535 {
536 case PowerState::on:
537 case PowerState::transitionToOff:
538 case PowerState::gracefulTransitionToOff:
539 case PowerState::transitionToCycleOff:
540 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700541 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700542 return "xyz.openbmc_project.State.Chassis.PowerState.On";
543 break;
544 case PowerState::waitForPSPowerOK:
545 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700546 case PowerState::off:
547 case PowerState::cycleOff:
548 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
549 break;
550 default:
551 return "";
552 break;
553 }
554};
Naveen Moses117c34e2021-05-26 20:10:51 +0530555#ifdef CHASSIS_SYSTEM_RESET
556enum class SlotPowerState
557{
558 on,
559 off,
560};
561static SlotPowerState slotPowerState;
562static constexpr std::string_view getSlotState(const SlotPowerState state)
563{
564 switch (state)
565 {
566 case SlotPowerState::on:
567 return "xyz.openbmc_project.State.Chassis.PowerState.On";
568 break;
569 case SlotPowerState::off:
570 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
571 break;
572 default:
573 return "";
574 break;
575 }
576};
577static void setSlotPowerState(const SlotPowerState state)
578{
579 slotPowerState = state;
580 chassisSlotIface->set_property("CurrentPowerState",
581 std::string(getSlotState(slotPowerState)));
582 chassisSlotIface->set_property("LastStateChangeTime", getCurrentTimeMs());
583}
584#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700585static void savePowerState(const PowerState state)
586{
587 powerStateSaveTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -0700588 std::chrono::milliseconds(TimerMap["PowerOffSaveMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700589 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
590 if (ec)
591 {
592 // operation_aborted is expected if timer is canceled before
593 // completion.
594 if (ec != boost::asio::error::operation_aborted)
595 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800596 lg2::error("Power-state save async_wait failed: {ERROR_MSG}",
597 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700598 }
599 return;
600 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300601 appState.set(PersistentState::Params::PowerState,
602 std::string{getChassisState(state)});
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700603 });
604}
605static void setPowerState(const PowerState state)
606{
607 powerState = state;
608 logStateTransition(state);
609
610 hostIface->set_property("CurrentHostState",
611 std::string(getHostState(powerState)));
612
613 chassisIface->set_property("CurrentPowerState",
614 std::string(getChassisState(powerState)));
615 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
616
617 // Save the power state for the restore policy
618 savePowerState(state);
619}
620
621enum class RestartCause
622{
623 command,
624 resetButton,
625 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700626 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700627 powerPolicyOn,
628 powerPolicyRestore,
629 softReset,
630};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700631static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700632static std::string getRestartCause(RestartCause cause)
633{
634 switch (cause)
635 {
636 case RestartCause::command:
637 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
638 break;
639 case RestartCause::resetButton:
640 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
641 break;
642 case RestartCause::powerButton:
643 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
644 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700645 case RestartCause::watchdog:
646 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
647 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700648 case RestartCause::powerPolicyOn:
Jason M. Bills418ce112021-09-08 15:15:05 -0700649 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyAlwaysOn";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700650 break;
651 case RestartCause::powerPolicyRestore:
Jason M. Bills418ce112021-09-08 15:15:05 -0700652 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyPreviousState";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700653 break;
654 case RestartCause::softReset:
655 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
656 break;
657 default:
658 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
659 break;
660 }
661}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700662static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700663{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700664 // Add this to the set of causes for this restart
665 causeSet.insert(cause);
666}
667static void clearRestartCause()
668{
669 // Clear the set for the next restart
670 causeSet.clear();
671}
672static void setRestartCauseProperty(const std::string& cause)
673{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800674 lg2::info("RestartCause set to {RESTART_CAUSE}", "RESTART_CAUSE", cause);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700675 restartCauseIface->set_property("RestartCause", cause);
676}
Rashmi RV89f61312020-01-22 15:41:50 +0530677
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300678#ifdef USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +0530679static void resetACBootProperty()
680{
681 if ((causeSet.contains(RestartCause::command)) ||
682 (causeSet.contains(RestartCause::softReset)))
683 {
684 conn->async_method_call(
685 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -0500686 if (ec)
687 {
688 lg2::error("failed to reset ACBoot property");
689 }
Patrick Williamsd394c882023-10-20 11:18:44 -0500690 },
Rashmi RV89f61312020-01-22 15:41:50 +0530691 "xyz.openbmc_project.Settings",
692 "/xyz/openbmc_project/control/host0/ac_boot",
693 "org.freedesktop.DBus.Properties", "Set",
694 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
695 std::variant<std::string>{"False"});
696 }
697}
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300698#endif // USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +0530699
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700700static void setRestartCause()
701{
702 // Determine the actual restart cause based on the set of causes
703 std::string restartCause =
704 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
705 if (causeSet.contains(RestartCause::watchdog))
706 {
707 restartCause = getRestartCause(RestartCause::watchdog);
708 }
709 else if (causeSet.contains(RestartCause::command))
710 {
711 restartCause = getRestartCause(RestartCause::command);
712 }
713 else if (causeSet.contains(RestartCause::resetButton))
714 {
715 restartCause = getRestartCause(RestartCause::resetButton);
716 }
717 else if (causeSet.contains(RestartCause::powerButton))
718 {
719 restartCause = getRestartCause(RestartCause::powerButton);
720 }
721 else if (causeSet.contains(RestartCause::powerPolicyOn))
722 {
723 restartCause = getRestartCause(RestartCause::powerPolicyOn);
724 }
725 else if (causeSet.contains(RestartCause::powerPolicyRestore))
726 {
727 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
728 }
729 else if (causeSet.contains(RestartCause::softReset))
730 {
Matt Simmering58e379d2022-09-23 14:45:50 -0700731#if IGNORE_SOFT_RESETS_DURING_POST
732 if (ignoreNextSoftReset)
733 {
734 ignoreNextSoftReset = false;
735 return;
736 }
737#endif
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700738 restartCause = getRestartCause(RestartCause::softReset);
739 }
740
741 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700742}
743
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700744static void systemPowerGoodFailedLog()
745{
746 sd_journal_send(
747 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
748 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
749 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700750 TimerMap["SioPowerGoodWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700751}
752
753static void psPowerOKFailedLog()
754{
755 sd_journal_send(
756 "MESSAGE=PowerControl: power supply power good failed to assert",
757 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
758 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700759 TimerMap["PsPowerOKWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700760}
761
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700762static void powerRestorePolicyLog()
763{
764 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
765 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
766 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
767}
768
769static void powerButtonPressLog()
770{
771 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
772 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
773 "OpenBMC.0.1.PowerButtonPressed", NULL);
774}
775
776static void resetButtonPressLog()
777{
778 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
779 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
780 "OpenBMC.0.1.ResetButtonPressed", NULL);
781}
782
783static void nmiButtonPressLog()
784{
785 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
786 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
787 "OpenBMC.0.1.NMIButtonPressed", NULL);
788}
789
790static void nmiDiagIntLog()
791{
792 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
793 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
794 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
795}
796
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300797PersistentState::PersistentState()
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700798{
799 // create the power control directory if it doesn't exist
800 std::error_code ec;
801 if (!(std::filesystem::create_directories(powerControlDir, ec)))
802 {
803 if (ec.value() != 0)
804 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800805 lg2::error("failed to create {DIR_NAME}: {ERROR_MSG}", "DIR_NAME",
806 powerControlDir.string(), "ERROR_MSG", ec.message());
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300807 throw std::runtime_error("Failed to create state directory");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700808 }
809 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300810
811 // read saved state, it's ok, if the file doesn't exists
812 std::ifstream appStateStream(powerControlDir / stateFile);
813 if (!appStateStream.is_open())
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700814 {
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300815 lg2::info("Cannot open state file \'{PATH}\'", "PATH",
816 std::string(powerControlDir / stateFile));
817 stateData = nlohmann::json({});
818 return;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700819 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300820 try
821 {
822 appStateStream >> stateData;
823 if (stateData.is_discarded())
824 {
825 lg2::info("Cannot parse state file \'{PATH}\'", "PATH",
826 std::string(powerControlDir / stateFile));
827 stateData = nlohmann::json({});
828 return;
829 }
830 }
831 catch (const std::exception& ex)
832 {
833 lg2::info("Cannot read state file \'{PATH}\'", "PATH",
834 std::string(powerControlDir / stateFile));
835 stateData = nlohmann::json({});
836 return;
837 }
838}
839PersistentState::~PersistentState()
840{
841 saveState();
842}
843const std::string PersistentState::get(Params parameter)
844{
845 auto val = stateData.find(getName(parameter));
846 if (val != stateData.end())
847 {
848 return val->get<std::string>();
849 }
850 return getDefault(parameter);
851}
852void PersistentState::set(Params parameter, const std::string& value)
853{
854 stateData[getName(parameter)] = value;
855 saveState();
856}
857
858const std::string PersistentState::getName(const Params parameter)
859{
860 switch (parameter)
861 {
862 case Params::PowerState:
863 return "PowerState";
864 }
865 return "";
866}
867const std::string PersistentState::getDefault(const Params parameter)
868{
869 switch (parameter)
870 {
871 case Params::PowerState:
872 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
873 }
874 return "";
875}
876void PersistentState::saveState()
877{
878 std::ofstream appStateStream(powerControlDir / stateFile, std::ios::trunc);
879 if (!appStateStream.is_open())
880 {
881 lg2::error("Cannot write state file \'{PATH}\'", "PATH",
882 std::string(powerControlDir / stateFile));
883 return;
884 }
885 appStateStream << stateData.dump(indentationSize);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700886}
887
Patrick Williams48aa1f02023-05-10 07:50:30 -0500888static constexpr const char* setingsService = "xyz.openbmc_project.Settings";
889static constexpr const char* powerRestorePolicyIface =
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300890 "xyz.openbmc_project.Control.Power.RestorePolicy";
891#ifdef USE_ACBOOT
Patrick Williams48aa1f02023-05-10 07:50:30 -0500892static constexpr const char* powerACBootObject =
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300893 "/xyz/openbmc_project/control/host0/ac_boot";
Patrick Williams48aa1f02023-05-10 07:50:30 -0500894static constexpr const char* powerACBootIface =
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300895 "xyz.openbmc_project.Common.ACBoot";
896#endif // USE_ACBOOT
897
898namespace match_rules = sdbusplus::bus::match::rules;
899
900static int powerRestoreConfigHandler(sd_bus_message* m, void* context,
901 sd_bus_error*)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700902{
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300903 if (context == nullptr || m == nullptr)
904 {
905 throw std::runtime_error("Invalid match");
906 }
Patrick Williams439b9c32022-07-22 19:26:53 -0500907 sdbusplus::message_t message(m);
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300908 PowerRestoreController* powerRestore =
909 static_cast<PowerRestoreController*>(context);
910
911 if (std::string(message.get_member()) == "InterfacesAdded")
912 {
913 sdbusplus::message::object_path path;
914 boost::container::flat_map<std::string, dbusPropertiesList> data;
915
916 message.read(path, data);
917
918 for (auto& [iface, properties] : data)
919 {
920 if ((iface == powerRestorePolicyIface)
921#ifdef USE_ACBOOT
922 || (iface == powerACBootIface)
923#endif // USE_ACBOOT
924 )
925 {
926 powerRestore->setProperties(properties);
927 }
928 }
929 }
930 else if (std::string(message.get_member()) == "PropertiesChanged")
931 {
932 std::string interfaceName;
933 dbusPropertiesList propertiesChanged;
934
935 message.read(interfaceName, propertiesChanged);
936
937 powerRestore->setProperties(propertiesChanged);
938 }
939 return 1;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700940}
941
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300942void PowerRestoreController::run()
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700943{
Patrick Williams48aa1f02023-05-10 07:50:30 -0500944 std::string powerRestorePolicyObject = "/xyz/openbmc_project/control/host" +
945 node + "/power_restore_policy";
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300946 powerRestorePolicyLog();
947 // this list only needs to be created once
948 if (matches.empty())
949 {
950 matches.emplace_back(
951 *conn,
952 match_rules::interfacesAdded() +
953 match_rules::argNpath(0, powerRestorePolicyObject) +
954 match_rules::sender(setingsService),
955 powerRestoreConfigHandler, this);
956#ifdef USE_ACBOOT
957 matches.emplace_back(*conn,
958 match_rules::interfacesAdded() +
959 match_rules::argNpath(0, powerACBootObject) +
960 match_rules::sender(setingsService),
961 powerRestoreConfigHandler, this);
962 matches.emplace_back(*conn,
963 match_rules::propertiesChanged(powerACBootObject,
964 powerACBootIface) +
965 match_rules::sender(setingsService),
966 powerRestoreConfigHandler, this);
967#endif // USE_ACBOOT
968 }
969
970 // Check if it's already on DBus
971 conn->async_method_call(
972 [this](boost::system::error_code ec,
973 const dbusPropertiesList properties) {
Patrick Williams48aa1f02023-05-10 07:50:30 -0500974 if (ec)
975 {
976 return;
977 }
978 setProperties(properties);
Patrick Williamsd394c882023-10-20 11:18:44 -0500979 },
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300980 setingsService, powerRestorePolicyObject,
981 "org.freedesktop.DBus.Properties", "GetAll", powerRestorePolicyIface);
982
983#ifdef USE_ACBOOT
984 // Check if it's already on DBus
985 conn->async_method_call(
986 [this](boost::system::error_code ec,
987 const dbusPropertiesList properties) {
Patrick Williams48aa1f02023-05-10 07:50:30 -0500988 if (ec)
989 {
990 return;
991 }
992 setProperties(properties);
Patrick Williamsd394c882023-10-20 11:18:44 -0500993 },
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300994 setingsService, powerACBootObject, "org.freedesktop.DBus.Properties",
995 "GetAll", powerACBootIface);
996#endif
997}
998
999void PowerRestoreController::setProperties(const dbusPropertiesList& props)
1000{
1001 for (auto& [property, propValue] : props)
1002 {
1003 if (property == "PowerRestorePolicy")
1004 {
1005 const std::string* value = std::get_if<std::string>(&propValue);
1006 if (value == nullptr)
1007 {
1008 lg2::error("Unable to read Power Restore Policy");
1009 continue;
1010 }
1011 powerRestorePolicy = *value;
1012 }
1013 else if (property == "PowerRestoreDelay")
1014 {
1015 const uint64_t* value = std::get_if<uint64_t>(&propValue);
1016 if (value == nullptr)
1017 {
1018 lg2::error("Unable to read Power Restore Delay");
1019 continue;
1020 }
1021 powerRestoreDelay = *value / 1000000; // usec to sec
1022 }
1023#ifdef USE_ACBOOT
1024 else if (property == "ACBoot")
1025 {
1026 const std::string* value = std::get_if<std::string>(&propValue);
1027 if (value == nullptr)
1028 {
1029 lg2::error("Unable to read AC Boot status");
1030 continue;
1031 }
1032 acBoot = *value;
1033 }
1034#endif // USE_ACBOOT
1035 }
1036 invokeIfReady();
1037}
1038
1039void PowerRestoreController::invokeIfReady()
1040{
1041 if ((powerRestorePolicy.empty()) || (powerRestoreDelay < 0))
1042 {
1043 return;
1044 }
1045#ifdef USE_ACBOOT
1046 if (acBoot.empty() || acBoot == "Unknown")
1047 {
1048 return;
1049 }
1050#endif
1051
1052 matches.clear();
1053 if (!timerFired)
1054 {
1055 // Calculate the delay from now to meet the requested delay
1056 // Subtract the approximate uboot time
1057 static constexpr const int ubootSeconds = 20;
1058 int delay = powerRestoreDelay - ubootSeconds;
1059 // Subtract the time since boot
1060 struct sysinfo info = {};
1061 if (sysinfo(&info) == 0)
1062 {
1063 delay -= info.uptime;
1064 }
1065
1066 if (delay > 0)
1067 {
1068 powerRestoreTimer.expires_after(std::chrono::seconds(delay));
1069 lg2::info("Power Restore delay of {DELAY} seconds started", "DELAY",
1070 delay);
Patrick Williams48aa1f02023-05-10 07:50:30 -05001071 powerRestoreTimer.async_wait(
1072 [this](const boost::system::error_code ec) {
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001073 if (ec)
1074 {
1075 // operation_aborted is expected if timer is canceled before
1076 // completion.
1077 if (ec == boost::asio::error::operation_aborted)
1078 {
1079 return;
1080 }
1081 lg2::error(
1082 "power restore policy async_wait failed: {ERROR_MSG}",
1083 "ERROR_MSG", ec.message());
1084 }
1085 else
1086 {
1087 lg2::info("Power Restore delay timer expired");
1088 }
1089 invoke();
1090 });
1091 timerFired = true;
1092 }
1093 else
1094 {
1095 invoke();
1096 }
1097 }
1098}
1099
1100void PowerRestoreController::invoke()
1101{
1102 // we want to run Power Restore only once
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001103 if (policyInvoked)
1104 {
1105 return;
1106 }
1107 policyInvoked = true;
1108
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001109 lg2::info("Invoking Power Restore Policy {POLICY}", "POLICY",
1110 powerRestorePolicy);
1111 if (powerRestorePolicy ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001112 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
1113 {
1114 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001115 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001116 }
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001117 else if (powerRestorePolicy ==
Jason M. Bills418ce112021-09-08 15:15:05 -07001118 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore")
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001119 {
1120 if (wasPowerDropped())
1121 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001122 lg2::info("Power was dropped, restoring Host On state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001123 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001124 setRestartCauseProperty(
1125 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001126 }
1127 else
1128 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001129 lg2::info("No power drop, restoring Host Off state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001130 }
1131 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -07001132 // We're done with the previous power state for the restore policy, so store
1133 // the current state
1134 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001135}
1136
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001137bool PowerRestoreController::wasPowerDropped()
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001138{
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001139 std::string state = appState.get(PersistentState::Params::PowerState);
1140 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001141}
1142
Zev Weiss676ef2c2021-09-02 21:54:02 -05001143static void waitForGPIOEvent(const std::string& name,
1144 const std::function<void(bool)>& eventHandler,
1145 gpiod::line& line,
1146 boost::asio::posix::stream_descriptor& event)
1147{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001148 event.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1149 [&name, eventHandler, &line,
1150 &event](const boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001151 if (ec)
1152 {
1153 lg2::error("{GPIO_NAME} fd handler error: {ERROR_MSG}", "GPIO_NAME",
1154 name, "ERROR_MSG", ec.message());
1155 // TODO: throw here to force power-control to
1156 // restart?
1157 return;
1158 }
1159 gpiod::line_event line_event = line.event_read();
1160 eventHandler(line_event.event_type == gpiod::line_event::RISING_EDGE);
1161 waitForGPIOEvent(name, eventHandler, line, event);
1162 });
Zev Weiss676ef2c2021-09-02 21:54:02 -05001163}
1164
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001165static bool requestGPIOEvents(
Zev Weiss676ef2c2021-09-02 21:54:02 -05001166 const std::string& name, const std::function<void(bool)>& handler,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001167 gpiod::line& gpioLine,
1168 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
1169{
1170 // Find the GPIO line
1171 gpioLine = gpiod::find_line(name);
1172 if (!gpioLine)
1173 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001174 lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001175 return false;
1176 }
1177
1178 try
1179 {
Andrei Kartashev3efcf372021-12-29 15:32:17 +03001180 gpioLine.request({appName, gpiod::line_request::EVENT_BOTH_EDGES, {}});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001181 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001182 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001183 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001184 lg2::error("Failed to request events for {GPIO_NAME}: {ERROR}",
1185 "GPIO_NAME", name, "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001186 return false;
1187 }
1188
1189 int gpioLineFd = gpioLine.event_get_fd();
1190 if (gpioLineFd < 0)
1191 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001192 lg2::error("Failed to get {GPIO_NAME} fd", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001193 return false;
1194 }
1195
1196 gpioEventDescriptor.assign(gpioLineFd);
1197
Zev Weiss676ef2c2021-09-02 21:54:02 -05001198 waitForGPIOEvent(name, handler, gpioLine, gpioEventDescriptor);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001199 return true;
1200}
1201
1202static bool setGPIOOutput(const std::string& name, const int value,
1203 gpiod::line& gpioLine)
1204{
1205 // Find the GPIO line
1206 gpioLine = gpiod::find_line(name);
1207 if (!gpioLine)
1208 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001209 lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001210 return false;
1211 }
1212
1213 // Request GPIO output to specified value
1214 try
1215 {
Andrei Kartashev3efcf372021-12-29 15:32:17 +03001216 gpioLine.request({appName, gpiod::line_request::DIRECTION_OUTPUT, {}},
1217 value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001218 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001219 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001220 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001221 lg2::error("Failed to request {GPIO_NAME} output: {ERROR}", "GPIO_NAME",
1222 name, "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001223 return false;
1224 }
1225
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001226 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1227 "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001228 return true;
1229}
1230
1231static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1232 const std::string& name, const int value,
1233 const int durationMs)
1234{
1235 // Set the masked GPIO line to the specified value
1236 maskedGPIOLine.set_value(value);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001237 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1238 "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001239 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001240 gpioAssertTimer.async_wait(
1241 [maskedGPIOLine, value, name](const boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001242 // Set the masked GPIO line back to the opposite value
1243 maskedGPIOLine.set_value(!value);
1244 lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
1245 if (ec)
1246 {
1247 // operation_aborted is expected if timer is canceled before
1248 // completion.
1249 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001250 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001251 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1252 "GPIO_NAME", name, "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001253 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05001254 }
1255 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001256 return 0;
1257}
1258
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001259static int setGPIOOutputForMs(const ConfigData& config, const int value,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001260 const int durationMs)
1261{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001262 // If the requested GPIO is masked, use the mask line to set the output
1263 if (powerButtonMask && config.lineName == powerOutConfig.lineName)
1264 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001265 return setMaskedGPIOOutputForMs(powerButtonMask, config.lineName, value,
1266 durationMs);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001267 }
1268 if (resetButtonMask && config.lineName == resetOutConfig.lineName)
1269 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001270 return setMaskedGPIOOutputForMs(resetButtonMask, config.lineName, value,
1271 durationMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001272 }
1273
1274 // No mask set, so request and set the GPIO normally
1275 gpiod::line gpioLine;
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001276 if (!setGPIOOutput(config.lineName, value, gpioLine))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001277 {
1278 return -1;
1279 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001280 const std::string name = config.lineName;
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001281
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001282 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001283 gpioAssertTimer.async_wait(
1284 [gpioLine, value, name](const boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001285 // Set the GPIO line back to the opposite value
1286 gpioLine.set_value(!value);
1287 lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
1288 if (ec)
1289 {
1290 // operation_aborted is expected if timer is canceled before
1291 // completion.
1292 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001293 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001294 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1295 "GPIO_NAME", name, "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001296 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05001297 }
1298 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001299 return 0;
1300}
1301
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001302static int assertGPIOForMs(const ConfigData& config, const int durationMs)
1303{
1304 return setGPIOOutputForMs(config, config.polarity, durationMs);
1305}
1306
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001307static void powerOn()
1308{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001309 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001310}
Naveen Moses117c34e2021-05-26 20:10:51 +05301311#ifdef CHASSIS_SYSTEM_RESET
1312static int slotPowerOn()
1313{
1314 if (power_control::slotPowerState != power_control::SlotPowerState::on)
1315 {
Naveen Moses117c34e2021-05-26 20:10:51 +05301316 slotPowerLine.set_value(1);
1317
1318 if (slotPowerLine.get_value() > 0)
1319 {
1320 setSlotPowerState(SlotPowerState::on);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001321 lg2::info("Slot Power is switched On\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301322 }
1323 else
1324 {
1325 return -1;
1326 }
1327 }
1328 else
1329 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001330 lg2::info("Slot Power is already in 'On' state\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301331 return -1;
1332 }
1333 return 0;
1334}
1335static int slotPowerOff()
1336{
1337 if (power_control::slotPowerState != power_control::SlotPowerState::off)
1338 {
1339 slotPowerLine.set_value(0);
1340
1341 if (!(slotPowerLine.get_value() > 0))
1342 {
1343 setSlotPowerState(SlotPowerState::off);
1344 setPowerState(PowerState::off);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001345 lg2::info("Slot Power is switched Off\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301346 }
1347 else
1348 {
1349 return -1;
1350 }
1351 }
1352 else
1353 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001354 lg2::info("Slot Power is already in 'Off' state\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301355 return -1;
1356 }
1357 return 0;
1358}
1359static void slotPowerCycle()
1360{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001361 lg2::info("Slot Power Cycle started\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301362 slotPowerOff();
1363 slotPowerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001364 std::chrono::milliseconds(TimerMap["SlotPowerCycleMs"]));
Naveen Moses117c34e2021-05-26 20:10:51 +05301365 slotPowerCycleTimer.async_wait([](const boost::system::error_code ec) {
1366 if (ec)
1367 {
1368 if (ec != boost::asio::error::operation_aborted)
1369 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001370 lg2::error(
1371 "Slot Power cycle timer async_wait failed: {ERROR_MSG}",
1372 "ERROR_MSG", ec.message());
Naveen Moses117c34e2021-05-26 20:10:51 +05301373 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001374 lg2::info("Slot Power cycle timer canceled\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301375 return;
1376 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001377 lg2::info("Slot Power cycle timer completed\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301378 slotPowerOn();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001379 lg2::info("Slot Power Cycle Completed\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301380 });
1381}
1382#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001383static void gracefulPowerOff()
1384{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001385 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001386}
1387
1388static void forcePowerOff()
1389{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001390 if (assertGPIOForMs(powerOutConfig, TimerMap["ForceOffPulseMs"]) < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001391 {
1392 return;
1393 }
1394
Jason M. Billsc6961b62021-10-21 14:08:02 -07001395 // If the force off timer expires, then the power-button override failed
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001396 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1397 if (ec)
1398 {
1399 // operation_aborted is expected if timer is canceled before
1400 // completion.
1401 if (ec != boost::asio::error::operation_aborted)
1402 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001403 lg2::error("Force power off async_wait failed: {ERROR_MSG}",
1404 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001405 }
1406 return;
1407 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001408
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001409 lg2::error("Power-button override failed. Not sure what to do now.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001410 });
1411}
1412
1413static void reset()
1414{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001415 assertGPIOForMs(resetOutConfig, TimerMap["ResetPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001416}
1417
1418static void gracefulPowerOffTimerStart()
1419{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001420 lg2::info("Graceful power-off timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001421 gracefulPowerOffTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001422 std::chrono::seconds(TimerMap["GracefulPowerOffS"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001423 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1424 if (ec)
1425 {
1426 // operation_aborted is expected if timer is canceled before
1427 // completion.
1428 if (ec != boost::asio::error::operation_aborted)
1429 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001430 lg2::error("Graceful power-off async_wait failed: {ERROR_MSG}",
1431 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001432 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001433 lg2::info("Graceful power-off timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001434 return;
1435 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001436 lg2::info("Graceful power-off timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001437 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1438 });
1439}
1440
1441static void powerCycleTimerStart()
1442{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001443 lg2::info("Power-cycle timer started");
Priyatharshan P70120512020-09-16 18:47:20 +05301444 powerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001445 std::chrono::milliseconds(TimerMap["PowerCycleMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001446 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1447 if (ec)
1448 {
1449 // operation_aborted is expected if timer is canceled before
1450 // completion.
1451 if (ec != boost::asio::error::operation_aborted)
1452 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001453 lg2::error("Power-cycle async_wait failed: {ERROR_MSG}",
1454 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001455 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001456 lg2::info("Power-cycle timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001457 return;
1458 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001459 lg2::info("Power-cycle timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001460 sendPowerControlEvent(Event::powerCycleTimerExpired);
1461 });
1462}
1463
1464static void psPowerOKWatchdogTimerStart()
1465{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001466 lg2::info("power supply power OK watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001467 psPowerOKWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001468 std::chrono::milliseconds(TimerMap["PsPowerOKWatchdogMs"]));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001469 psPowerOKWatchdogTimer.async_wait([](const boost::system::error_code ec) {
1470 if (ec)
1471 {
1472 // operation_aborted is expected if timer is canceled before
1473 // completion.
1474 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001475 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001476 lg2::error(
1477 "power supply power OK watchdog async_wait failed: {ERROR_MSG}",
1478 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001479 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001480 lg2::info("power supply power OK watchdog timer canceled");
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001481 return;
1482 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001483 lg2::info("power supply power OK watchdog timer expired");
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001484 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1485 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001486}
1487
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001488static void warmResetCheckTimerStart()
1489{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001490 lg2::info("Warm reset check timer started");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001491 warmResetCheckTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001492 std::chrono::milliseconds(TimerMap["WarmResetCheckMs"]));
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001493 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1494 if (ec)
1495 {
1496 // operation_aborted is expected if timer is canceled before
1497 // completion.
1498 if (ec != boost::asio::error::operation_aborted)
1499 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001500 lg2::error("Warm reset check async_wait failed: {ERROR_MSG}",
1501 "ERROR_MSG", ec.message());
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001502 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001503 lg2::info("Warm reset check timer canceled");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001504 return;
1505 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001506 lg2::info("Warm reset check timer completed");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001507 sendPowerControlEvent(Event::warmResetDetected);
1508 });
1509}
1510
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001511static void pohCounterTimerStart()
1512{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001513 lg2::info("POH timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001514 // Set the time-out as 1 hour, to align with POH command in ipmid
1515 pohCounterTimer.expires_after(std::chrono::hours(1));
1516 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1517 if (ec)
1518 {
1519 // operation_aborted is expected if timer is canceled before
1520 // completion.
1521 if (ec != boost::asio::error::operation_aborted)
1522 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001523 lg2::error("POH timer async_wait failed: {ERROR_MSG}",
1524 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001525 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001526 lg2::info("POH timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001527 return;
1528 }
1529
1530 if (getHostState(powerState) !=
1531 "xyz.openbmc_project.State.Host.HostState.Running")
1532 {
1533 return;
1534 }
1535
1536 conn->async_method_call(
1537 [](boost::system::error_code ec,
1538 const std::variant<uint32_t>& pohCounterProperty) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001539 if (ec)
1540 {
1541 lg2::error("error getting poh counter");
1542 return;
1543 }
1544 const uint32_t* pohCounter =
1545 std::get_if<uint32_t>(&pohCounterProperty);
1546 if (pohCounter == nullptr)
1547 {
1548 lg2::error("unable to read poh counter");
1549 return;
1550 }
1551
1552 conn->async_method_call(
1553 [](boost::system::error_code ec) {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001554 if (ec)
1555 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001556 lg2::error("failed to set poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001557 }
Patrick Williamsd394c882023-10-20 11:18:44 -05001558 },
Patrick Williams48aa1f02023-05-10 07:50:30 -05001559 "xyz.openbmc_project.Settings",
1560 "/xyz/openbmc_project/state/chassis0",
1561 "org.freedesktop.DBus.Properties", "Set",
1562 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1563 std::variant<uint32_t>(*pohCounter + 1));
Patrick Williamsd394c882023-10-20 11:18:44 -05001564 },
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001565 "xyz.openbmc_project.Settings",
1566 "/xyz/openbmc_project/state/chassis0",
1567 "org.freedesktop.DBus.Properties", "Get",
1568 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1569
1570 pohCounterTimerStart();
1571 });
1572}
1573
1574static void currentHostStateMonitor()
1575{
Yong Li8d660212019-12-27 10:18:10 +08001576 if (getHostState(powerState) ==
1577 "xyz.openbmc_project.State.Host.HostState.Running")
1578 {
1579 pohCounterTimerStart();
1580 // Clear the restart cause set for the next restart
1581 clearRestartCause();
1582 }
1583 else
1584 {
1585 pohCounterTimer.cancel();
1586 // Set the restart cause set for this restart
1587 setRestartCause();
1588 }
1589
Patrick Williams48aa1f02023-05-10 07:50:30 -05001590 static auto match =
1591 sdbusplus::bus::match_t(*conn,
1592 "type='signal',member='PropertiesChanged', "
1593 "interface='org.freedesktop.DBus.Properties', "
1594 "arg0='xyz.openbmc_project.State.Host'",
1595 [](sdbusplus::message_t& message) {
1596 std::string intfName;
1597 std::map<std::string, std::variant<std::string>> properties;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001598
Patrick Williams48aa1f02023-05-10 07:50:30 -05001599 try
1600 {
1601 message.read(intfName, properties);
1602 }
1603 catch (const std::exception& e)
1604 {
1605 lg2::error("Unable to read host state: {ERROR}", "ERROR", e);
1606 return;
1607 }
1608 if (properties.empty())
1609 {
1610 lg2::error("ERROR: Empty PropertiesChanged signal received");
1611 return;
1612 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001613
Patrick Williams48aa1f02023-05-10 07:50:30 -05001614 // We only want to check for CurrentHostState
1615 if (properties.begin()->first != "CurrentHostState")
1616 {
1617 return;
1618 }
1619 std::string* currentHostState =
1620 std::get_if<std::string>(&(properties.begin()->second));
1621 if (currentHostState == nullptr)
1622 {
1623 lg2::error("{PROPERTY} property invalid", "PROPERTY",
1624 properties.begin()->first);
1625 return;
1626 }
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001627
Patrick Williams48aa1f02023-05-10 07:50:30 -05001628 if (*currentHostState ==
1629 "xyz.openbmc_project.State.Host.HostState.Running")
1630 {
1631 pohCounterTimerStart();
1632 // Clear the restart cause set for the next restart
1633 clearRestartCause();
1634 sd_journal_send("MESSAGE=Host system DC power is on", "PRIORITY=%i",
1635 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
1636 "OpenBMC.0.1.DCPowerOn", NULL);
1637 }
1638 else
1639 {
1640 pohCounterTimer.cancel();
1641 // POST_COMPLETE GPIO event is not working in some platforms
1642 // when power state is changed to OFF. This resulted in
1643 // 'OperatingSystemState' to stay at 'Standby', even though
1644 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1645 // if HostState is trurned to OFF.
1646 setOperatingSystemState(OperatingSystemStateStage::Inactive);
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301647
Patrick Williams48aa1f02023-05-10 07:50:30 -05001648 // Set the restart cause set for this restart
1649 setRestartCause();
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001650#ifdef USE_ACBOOT
Patrick Williams48aa1f02023-05-10 07:50:30 -05001651 resetACBootProperty();
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001652#endif // USE_ACBOOT
Patrick Williams48aa1f02023-05-10 07:50:30 -05001653 sd_journal_send("MESSAGE=Host system DC power is off",
1654 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
1655 "OpenBMC.0.1.DCPowerOff", NULL);
1656 }
Patrick Williamsd394c882023-10-20 11:18:44 -05001657 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001658}
1659
1660static void sioPowerGoodWatchdogTimerStart()
1661{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001662 lg2::info("SIO power good watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001663 sioPowerGoodWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001664 std::chrono::milliseconds(TimerMap["SioPowerGoodWatchdogMs"]));
Patrick Williams48aa1f02023-05-10 07:50:30 -05001665 sioPowerGoodWatchdogTimer.async_wait(
1666 [](const boost::system::error_code ec) {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001667 if (ec)
1668 {
1669 // operation_aborted is expected if timer is canceled before
1670 // completion.
1671 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001672 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001673 lg2::error(
1674 "SIO power good watchdog async_wait failed: {ERROR_MSG}",
1675 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001676 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001677 lg2::info("SIO power good watchdog timer canceled");
1678 return;
1679 }
1680 lg2::info("SIO power good watchdog timer completed");
1681 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1682 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001683}
1684
1685static void powerStateOn(const Event event)
1686{
1687 logEvent(__FUNCTION__, event);
1688 switch (event)
1689 {
1690 case Event::psPowerOKDeAssert:
1691 setPowerState(PowerState::off);
1692 // DC power is unexpectedly lost, beep
1693 beep(beepPowerFail);
1694 break;
1695 case Event::sioS5Assert:
1696 setPowerState(PowerState::transitionToOff);
Matt Simmering58e379d2022-09-23 14:45:50 -07001697#if IGNORE_SOFT_RESETS_DURING_POST
1698 // Only recognize soft resets once host gets past POST COMPLETE
1699 if (operatingSystemState != OperatingSystemStateStage::Standby)
1700 {
1701 ignoreNextSoftReset = true;
1702 }
1703#endif
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001704 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001705 break;
Jason M. Billsfb957332021-01-28 13:18:46 -08001706#if USE_PLT_RST
1707 case Event::pltRstAssert:
1708#else
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001709 case Event::postCompleteDeAssert:
Jason M. Billsfb957332021-01-28 13:18:46 -08001710#endif
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001711 setPowerState(PowerState::checkForWarmReset);
Matt Simmering58e379d2022-09-23 14:45:50 -07001712#if IGNORE_SOFT_RESETS_DURING_POST
1713 // Only recognize soft resets once host gets past POST COMPLETE
1714 if (operatingSystemState != OperatingSystemStateStage::Standby)
1715 {
1716 ignoreNextSoftReset = true;
1717 }
1718#endif
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001719 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001720 warmResetCheckTimerStart();
1721 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001722 case Event::powerButtonPressed:
1723 setPowerState(PowerState::gracefulTransitionToOff);
1724 gracefulPowerOffTimerStart();
1725 break;
1726 case Event::powerOffRequest:
1727 setPowerState(PowerState::transitionToOff);
1728 forcePowerOff();
1729 break;
1730 case Event::gracefulPowerOffRequest:
1731 setPowerState(PowerState::gracefulTransitionToOff);
1732 gracefulPowerOffTimerStart();
1733 gracefulPowerOff();
1734 break;
1735 case Event::powerCycleRequest:
1736 setPowerState(PowerState::transitionToCycleOff);
1737 forcePowerOff();
1738 break;
1739 case Event::gracefulPowerCycleRequest:
1740 setPowerState(PowerState::gracefulTransitionToCycleOff);
1741 gracefulPowerOffTimerStart();
1742 gracefulPowerOff();
1743 break;
Jayanth Othayothdc0bab92024-02-07 07:24:35 -06001744 case Event::resetButtonPressed:
1745 setPowerState(PowerState::checkForWarmReset);
1746 warmResetCheckTimerStart();
1747 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001748 case Event::resetRequest:
1749 reset();
1750 break;
1751 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001752 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001753 break;
1754 }
1755}
1756
1757static void powerStateWaitForPSPowerOK(const Event event)
1758{
1759 logEvent(__FUNCTION__, event);
1760 switch (event)
1761 {
1762 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301763 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001764 // Cancel any GPIO assertions held during the transition
1765 gpioAssertTimer.cancel();
1766 psPowerOKWatchdogTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301767 if (sioEnabled == true)
1768 {
1769 sioPowerGoodWatchdogTimerStart();
1770 setPowerState(PowerState::waitForSIOPowerGood);
1771 }
1772 else
1773 {
1774 setPowerState(PowerState::on);
1775 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001776 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301777 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001778 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001779 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001780 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001781 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001782 case Event::sioPowerGoodAssert:
1783 psPowerOKWatchdogTimer.cancel();
1784 setPowerState(PowerState::on);
1785 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001786 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001787 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001788 break;
1789 }
1790}
1791
1792static void powerStateWaitForSIOPowerGood(const Event event)
1793{
1794 logEvent(__FUNCTION__, event);
1795 switch (event)
1796 {
1797 case Event::sioPowerGoodAssert:
1798 sioPowerGoodWatchdogTimer.cancel();
1799 setPowerState(PowerState::on);
1800 break;
1801 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001802 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001803 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001804 break;
1805 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001806 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001807 break;
1808 }
1809}
1810
1811static void powerStateOff(const Event event)
1812{
1813 logEvent(__FUNCTION__, event);
1814 switch (event)
1815 {
1816 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301817 {
1818 if (sioEnabled == true)
1819 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001820 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301821 setPowerState(PowerState::waitForSIOPowerGood);
1822 }
1823 else
1824 {
1825 setPowerState(PowerState::on);
1826 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001827 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301828 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001829 case Event::sioS5DeAssert:
Jason M. Billsfe159032022-09-01 16:03:37 -07001830 psPowerOKWatchdogTimerStart();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001831 setPowerState(PowerState::waitForPSPowerOK);
1832 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001833 case Event::sioPowerGoodAssert:
1834 setPowerState(PowerState::on);
1835 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001836 case Event::powerButtonPressed:
1837 psPowerOKWatchdogTimerStart();
1838 setPowerState(PowerState::waitForPSPowerOK);
1839 break;
1840 case Event::powerOnRequest:
1841 psPowerOKWatchdogTimerStart();
1842 setPowerState(PowerState::waitForPSPowerOK);
1843 powerOn();
1844 break;
1845 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001846 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001847 break;
1848 }
1849}
1850
1851static void powerStateTransitionToOff(const Event event)
1852{
1853 logEvent(__FUNCTION__, event);
1854 switch (event)
1855 {
1856 case Event::psPowerOKDeAssert:
1857 // Cancel any GPIO assertions held during the transition
1858 gpioAssertTimer.cancel();
1859 setPowerState(PowerState::off);
1860 break;
1861 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001862 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001863 break;
1864 }
1865}
1866
1867static void powerStateGracefulTransitionToOff(const Event event)
1868{
1869 logEvent(__FUNCTION__, event);
1870 switch (event)
1871 {
1872 case Event::psPowerOKDeAssert:
1873 gracefulPowerOffTimer.cancel();
1874 setPowerState(PowerState::off);
1875 break;
1876 case Event::gracefulPowerOffTimerExpired:
1877 setPowerState(PowerState::on);
1878 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001879 case Event::powerOffRequest:
1880 gracefulPowerOffTimer.cancel();
1881 setPowerState(PowerState::transitionToOff);
1882 forcePowerOff();
1883 break;
1884 case Event::powerCycleRequest:
1885 gracefulPowerOffTimer.cancel();
1886 setPowerState(PowerState::transitionToCycleOff);
1887 forcePowerOff();
1888 break;
1889 case Event::resetRequest:
1890 gracefulPowerOffTimer.cancel();
1891 setPowerState(PowerState::on);
1892 reset();
1893 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001894 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001895 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001896 break;
1897 }
1898}
1899
1900static void powerStateCycleOff(const Event event)
1901{
1902 logEvent(__FUNCTION__, event);
1903 switch (event)
1904 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001905 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301906 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001907 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301908 if (sioEnabled == true)
1909 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001910 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301911 setPowerState(PowerState::waitForSIOPowerGood);
1912 }
1913 else
1914 {
1915 setPowerState(PowerState::on);
1916 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001917 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301918 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001919 case Event::sioS5DeAssert:
1920 powerCycleTimer.cancel();
Jason M. Billsfe159032022-09-01 16:03:37 -07001921 psPowerOKWatchdogTimerStart();
Jason M. Bills35aa6652020-04-30 16:24:55 -07001922 setPowerState(PowerState::waitForPSPowerOK);
1923 break;
1924 case Event::powerButtonPressed:
1925 powerCycleTimer.cancel();
1926 psPowerOKWatchdogTimerStart();
1927 setPowerState(PowerState::waitForPSPowerOK);
1928 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001929 case Event::powerCycleTimerExpired:
1930 psPowerOKWatchdogTimerStart();
1931 setPowerState(PowerState::waitForPSPowerOK);
1932 powerOn();
1933 break;
1934 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001935 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001936 break;
1937 }
1938}
1939
1940static void powerStateTransitionToCycleOff(const Event event)
1941{
1942 logEvent(__FUNCTION__, event);
1943 switch (event)
1944 {
1945 case Event::psPowerOKDeAssert:
1946 // Cancel any GPIO assertions held during the transition
1947 gpioAssertTimer.cancel();
1948 setPowerState(PowerState::cycleOff);
1949 powerCycleTimerStart();
1950 break;
1951 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001952 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001953 break;
1954 }
1955}
1956
1957static void powerStateGracefulTransitionToCycleOff(const Event event)
1958{
1959 logEvent(__FUNCTION__, event);
1960 switch (event)
1961 {
1962 case Event::psPowerOKDeAssert:
1963 gracefulPowerOffTimer.cancel();
1964 setPowerState(PowerState::cycleOff);
1965 powerCycleTimerStart();
1966 break;
1967 case Event::gracefulPowerOffTimerExpired:
1968 setPowerState(PowerState::on);
1969 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001970 case Event::powerOffRequest:
1971 gracefulPowerOffTimer.cancel();
1972 setPowerState(PowerState::transitionToOff);
1973 forcePowerOff();
1974 break;
1975 case Event::powerCycleRequest:
1976 gracefulPowerOffTimer.cancel();
1977 setPowerState(PowerState::transitionToCycleOff);
1978 forcePowerOff();
1979 break;
1980 case Event::resetRequest:
1981 gracefulPowerOffTimer.cancel();
1982 setPowerState(PowerState::on);
1983 reset();
1984 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001985 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001986 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001987 break;
1988 }
1989}
1990
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001991static void powerStateCheckForWarmReset(const Event event)
1992{
1993 logEvent(__FUNCTION__, event);
1994 switch (event)
1995 {
1996 case Event::sioS5Assert:
1997 warmResetCheckTimer.cancel();
1998 setPowerState(PowerState::transitionToOff);
1999 break;
2000 case Event::warmResetDetected:
2001 setPowerState(PowerState::on);
2002 break;
P.K. Lee344dae82019-11-27 16:35:05 +08002003 case Event::psPowerOKDeAssert:
2004 warmResetCheckTimer.cancel();
2005 setPowerState(PowerState::off);
2006 // DC power is unexpectedly lost, beep
2007 beep(beepPowerFail);
2008 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002009 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002010 lg2::info("No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002011 break;
2012 }
2013}
2014
Zev Weiss584aa132021-09-02 19:21:52 -05002015static void psPowerOKHandler(bool state)
2016{
Zev Weissedc86f32024-05-07 01:44:33 +00002017 Event powerControlEvent = (state == powerOkConfig.polarity)
2018 ? Event::psPowerOKAssert
2019 : Event::psPowerOKDeAssert;
Zev Weiss584aa132021-09-02 19:21:52 -05002020 sendPowerControlEvent(powerControlEvent);
2021}
2022
Zev Weiss584aa132021-09-02 19:21:52 -05002023static void sioPowerGoodHandler(bool state)
2024{
Zev Weissedc86f32024-05-07 01:44:33 +00002025 Event powerControlEvent = (state == sioPwrGoodConfig.polarity)
2026 ? Event::sioPowerGoodAssert
2027 : Event::sioPowerGoodDeAssert;
Zev Weiss584aa132021-09-02 19:21:52 -05002028 sendPowerControlEvent(powerControlEvent);
2029}
2030
Zev Weiss584aa132021-09-02 19:21:52 -05002031static void sioOnControlHandler(bool state)
2032{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002033 lg2::info("SIO_ONCONTROL value changed: {VALUE}", "VALUE",
2034 static_cast<int>(state));
Zev Weiss584aa132021-09-02 19:21:52 -05002035}
2036
Zev Weiss584aa132021-09-02 19:21:52 -05002037static void sioS5Handler(bool state)
2038{
Zev Weissedc86f32024-05-07 01:44:33 +00002039 Event powerControlEvent = (state == sioS5Config.polarity)
2040 ? Event::sioS5Assert
2041 : Event::sioS5DeAssert;
Zev Weiss584aa132021-09-02 19:21:52 -05002042 sendPowerControlEvent(powerControlEvent);
2043}
2044
Zev Weiss584aa132021-09-02 19:21:52 -05002045static void powerButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002046{
Zev Weissedc86f32024-05-07 01:44:33 +00002047 bool asserted = state == powerButtonConfig.polarity;
2048 powerButtonIface->set_property("ButtonPressed", asserted);
2049 if (asserted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002050 {
2051 powerButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002052 if (!powerButtonMask)
2053 {
2054 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002055 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002056 }
2057 else
2058 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002059 lg2::info("power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002060 }
2061 }
Zev Weiss584aa132021-09-02 19:21:52 -05002062}
2063
Zev Weiss584aa132021-09-02 19:21:52 -05002064static void resetButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002065{
Zev Weissedc86f32024-05-07 01:44:33 +00002066 bool asserted = state == resetButtonConfig.polarity;
2067 resetButtonIface->set_property("ButtonPressed", asserted);
2068 if (asserted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002069 {
2070 resetButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002071 if (!resetButtonMask)
2072 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002073 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002074 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002075 }
2076 else
2077 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002078 lg2::info("reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002079 }
2080 }
Zev Weiss584aa132021-09-02 19:21:52 -05002081}
2082
Vijay Khemka04175c22020-10-09 14:28:11 -07002083#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002084static constexpr auto systemdBusname = "org.freedesktop.systemd1";
2085static constexpr auto systemdPath = "/org/freedesktop/systemd1";
2086static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
2087static constexpr auto systemTargetName = "chassis-system-reset.target";
2088
2089void systemReset()
2090{
2091 conn->async_method_call(
2092 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002093 if (ec)
2094 {
2095 lg2::error("Failed to call chassis system reset: {ERR}", "ERR",
2096 ec.message());
2097 }
Patrick Williamsd394c882023-10-20 11:18:44 -05002098 },
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002099 systemdBusname, systemdPath, systemdInterface, "StartUnit",
2100 systemTargetName, "replace");
2101}
Vijay Khemka04175c22020-10-09 14:28:11 -07002102#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002103
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002104static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002105{
2106 conn->async_method_call(
2107 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002108 if (ec)
2109 {
2110 lg2::error("failed to set NMI source");
2111 }
Patrick Williamsd394c882023-10-20 11:18:44 -05002112 },
Chen Yugang303bd582019-11-01 08:45:06 +08002113 "xyz.openbmc_project.Settings",
2114 "/xyz/openbmc_project/Chassis/Control/NMISource",
2115 "org.freedesktop.DBus.Properties", "Set",
2116 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
2117 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002118}
2119
2120static void nmiReset(void)
2121{
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002122 const static constexpr int nmiOutPulseTimeMs = 200;
2123
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002124 lg2::info("NMI out action");
Jian Zhang461a1662022-09-22 11:29:01 +08002125 nmiOutLine.set_value(nmiOutConfig.polarity);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002126 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME",
Jian Zhang461a1662022-09-22 11:29:01 +08002127 nmiOutConfig.lineName, "GPIO_VALUE", nmiOutConfig.polarity);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002128 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2129 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2130 // restore the NMI_OUT GPIO line back to the opposite value
Jian Zhang461a1662022-09-22 11:29:01 +08002131 nmiOutLine.set_value(!nmiOutConfig.polarity);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002132 lg2::info("{GPIO_NAME} released", "GPIO_NAME", nmiOutConfig.lineName);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002133 if (ec)
2134 {
2135 // operation_aborted is expected if timer is canceled before
2136 // completion.
2137 if (ec != boost::asio::error::operation_aborted)
2138 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002139 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
2140 "GPIO_NAME", nmiOutConfig.lineName, "ERROR_MSG",
2141 ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002142 }
2143 }
2144 });
2145 // log to redfish
2146 nmiDiagIntLog();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002147 lg2::info("NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002148 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002149 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002150}
2151
2152static void nmiSourcePropertyMonitor(void)
2153{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002154 lg2::info("NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002155
Patrick Williams439b9c32022-07-22 19:26:53 -05002156 static std::unique_ptr<sdbusplus::bus::match_t> nmiSourceMatch =
2157 std::make_unique<sdbusplus::bus::match_t>(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002158 *conn,
2159 "type='signal',interface='org.freedesktop.DBus.Properties',"
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002160 "member='PropertiesChanged',"
2161 "arg0namespace='xyz.openbmc_project.Chassis.Control.NMISource'",
Patrick Williams439b9c32022-07-22 19:26:53 -05002162 [](sdbusplus::message_t& msg) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002163 std::string interfaceName;
2164 boost::container::flat_map<std::string, std::variant<bool, std::string>>
2165 propertiesChanged;
2166 std::string state;
2167 bool value = true;
2168 try
2169 {
2170 msg.read(interfaceName, propertiesChanged);
2171 if (propertiesChanged.begin()->first == "Enabled")
2172 {
2173 value = std::get<bool>(propertiesChanged.begin()->second);
2174 lg2::info("NMI Enabled propertiesChanged value: {VALUE}",
2175 "VALUE", value);
2176 nmiEnabled = value;
2177 if (nmiEnabled)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002178 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002179 nmiReset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002180 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05002181 }
2182 }
2183 catch (const std::exception& e)
2184 {
2185 lg2::error("Unable to read NMI source: {ERROR}", "ERROR", e);
2186 return;
2187 }
Patrick Williamsd394c882023-10-20 11:18:44 -05002188 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002189}
2190
2191static void setNmiSource()
2192{
2193 conn->async_method_call(
2194 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002195 if (ec)
2196 {
2197 lg2::error("failed to set NMI source");
2198 }
Patrick Williamsd394c882023-10-20 11:18:44 -05002199 },
Chen Yugang303bd582019-11-01 08:45:06 +08002200 "xyz.openbmc_project.Settings",
2201 "/xyz/openbmc_project/Chassis/Control/NMISource",
2202 "org.freedesktop.DBus.Properties", "Set",
2203 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
Jason M. Bills418ce112021-09-08 15:15:05 -07002204 std::variant<std::string>{
Tim Lee6af569f2024-03-11 17:32:42 +08002205 "xyz.openbmc_project.Chassis.Control.NMISource.BMCSourceSignal.FrontPanelButton"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002206 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002207 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002208}
2209
Zev Weiss584aa132021-09-02 19:21:52 -05002210static void nmiButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002211{
Olivier FAURAXd7ea2832023-04-14 14:08:02 +00002212 // Don't handle event if host not running and config doesn't force it
2213 if (!nmiWhenPoweredOff &&
2214 getHostState(powerState) !=
2215 "xyz.openbmc_project.State.Host.HostState.Running")
2216 {
2217 return;
2218 }
Zev Weissedc86f32024-05-07 01:44:33 +00002219
2220 bool asserted = state == nmiButtonConfig.polarity;
2221 nmiButtonIface->set_property("ButtonPressed", asserted);
2222 if (asserted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002223 {
2224 nmiButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002225 if (nmiButtonMasked)
2226 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002227 lg2::info("NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002228 }
2229 else
2230 {
2231 setNmiSource();
2232 }
2233 }
Zev Weiss584aa132021-09-02 19:21:52 -05002234}
2235
Zev Weiss584aa132021-09-02 19:21:52 -05002236static void idButtonHandler(bool state)
2237{
Zev Weissedc86f32024-05-07 01:44:33 +00002238 bool asserted = state == idButtonConfig.polarity;
2239 idButtonIface->set_property("ButtonPressed", asserted);
Zev Weiss584aa132021-09-02 19:21:52 -05002240}
2241
Jason M. Billsfb957332021-01-28 13:18:46 -08002242static void pltRstHandler(bool pltRst)
2243{
2244 if (pltRst)
2245 {
2246 sendPowerControlEvent(Event::pltRstDeAssert);
2247 }
2248 else
2249 {
2250 sendPowerControlEvent(Event::pltRstAssert);
2251 }
2252}
2253
Patrick Williams439b9c32022-07-22 19:26:53 -05002254[[maybe_unused]] static void hostMiscHandler(sdbusplus::message_t& msg)
Jason M. Billsfb957332021-01-28 13:18:46 -08002255{
2256 std::string interfaceName;
2257 boost::container::flat_map<std::string, std::variant<bool>>
2258 propertiesChanged;
Jason M. Billsfb957332021-01-28 13:18:46 -08002259 try
2260 {
2261 msg.read(interfaceName, propertiesChanged);
2262 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002263 catch (const std::exception& e)
Jason M. Billsfb957332021-01-28 13:18:46 -08002264 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002265 lg2::error("Unable to read Host Misc status: {ERROR}", "ERROR", e);
Jason M. Billsfb957332021-01-28 13:18:46 -08002266 return;
2267 }
2268 if (propertiesChanged.empty())
2269 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002270 lg2::error("ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002271 return;
2272 }
2273
2274 for (auto& [property, value] : propertiesChanged)
2275 {
2276 if (property == "ESpiPlatformReset")
2277 {
2278 bool* pltRst = std::get_if<bool>(&value);
2279 if (pltRst == nullptr)
2280 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002281 lg2::error("{PROPERTY} property invalid", "PROPERTY", property);
Jason M. Billsfb957332021-01-28 13:18:46 -08002282 return;
2283 }
2284 pltRstHandler(*pltRst);
2285 }
2286 }
2287}
2288
Zev Weiss584aa132021-09-02 19:21:52 -05002289static void postCompleteHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002290{
Zev Weissedc86f32024-05-07 01:44:33 +00002291 bool asserted = state == postCompleteConfig.polarity;
2292 if (asserted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002293 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002294 sendPowerControlEvent(Event::postCompleteAssert);
Tim Lee86239182021-12-23 11:46:01 +08002295 setOperatingSystemState(OperatingSystemStateStage::Standby);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002296 }
2297 else
2298 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002299 sendPowerControlEvent(Event::postCompleteDeAssert);
Tim Lee86239182021-12-23 11:46:01 +08002300 setOperatingSystemState(OperatingSystemStateStage::Inactive);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002301 }
Zev Weiss584aa132021-09-02 19:21:52 -05002302}
2303
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302304static int loadConfigValues()
2305{
2306 const std::string configFilePath =
2307 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2308 ".json";
2309 std::ifstream configFile(configFilePath.c_str());
2310 if (!configFile.is_open())
2311 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002312 lg2::error("loadConfigValues: Cannot open config path \'{PATH}\'",
2313 "PATH", configFilePath);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302314 return -1;
2315 }
Zev Weiss1aa08b22021-09-15 17:06:20 -05002316 auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302317
Priyatharshan P70120512020-09-16 18:47:20 +05302318 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302319 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002320 lg2::error("Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302321 return -1;
2322 }
Priyatharshan P70120512020-09-16 18:47:20 +05302323 auto gpios = jsonData["gpio_configs"];
2324 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302325
Priyatharshan P70120512020-09-16 18:47:20 +05302326 ConfigData* tempGpioData;
2327
2328 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302329 {
Priyatharshan P70120512020-09-16 18:47:20 +05302330 if (!gpioConfig.contains("Name"))
2331 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002332 lg2::error("The 'Name' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302333 return -1;
2334 }
2335
2336 // Iterate through the powersignal map to check if the gpio json config
2337 // entry is valid
2338 std::string gpioName = gpioConfig["Name"];
2339 auto signalMapIter = powerSignalMap.find(gpioName);
2340 if (signalMapIter == powerSignalMap.end())
2341 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002342 lg2::error(
2343 "{GPIO_NAME} is not a recognized power-control signal name",
2344 "GPIO_NAME", gpioName);
Priyatharshan P70120512020-09-16 18:47:20 +05302345 return -1;
2346 }
2347
2348 // assign the power signal name to the corresponding structure reference
2349 // from map then fillup the structure with coressponding json config
2350 // value
2351 tempGpioData = signalMapIter->second;
2352 tempGpioData->name = gpioName;
2353
2354 if (!gpioConfig.contains("Type"))
2355 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002356 lg2::error("The \'Type\' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302357 return -1;
2358 }
2359
2360 std::string signalType = gpioConfig["Type"];
2361 if (signalType == "GPIO")
2362 {
2363 tempGpioData->type = ConfigType::GPIO;
2364 }
2365 else if (signalType == "DBUS")
2366 {
2367 tempGpioData->type = ConfigType::DBUS;
2368 }
2369 else
2370 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002371 lg2::error("{TYPE} is not a recognized power-control signal type",
2372 "TYPE", signalType);
Priyatharshan P70120512020-09-16 18:47:20 +05302373 return -1;
2374 }
2375
2376 if (tempGpioData->type == ConfigType::GPIO)
2377 {
2378 if (gpioConfig.contains("LineName"))
2379 {
2380 tempGpioData->lineName = gpioConfig["LineName"];
2381 }
2382 else
2383 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002384 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002385 "The \'LineName\' field must be defined for GPIO configuration");
Priyatharshan P70120512020-09-16 18:47:20 +05302386 return -1;
2387 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002388 if (gpioConfig.contains("Polarity"))
2389 {
2390 std::string polarity = gpioConfig["Polarity"];
2391 if (polarity == "ActiveLow")
2392 {
2393 tempGpioData->polarity = false;
2394 }
2395 else if (polarity == "ActiveHigh")
2396 {
2397 tempGpioData->polarity = true;
2398 }
2399 else
2400 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002401 lg2::error(
2402 "Polarity defined but not properly setup. Please only ActiveHigh or ActiveLow. Currently set to {POLARITY}",
2403 "POLARITY", polarity);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002404 return -1;
2405 }
2406 }
2407 else
2408 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002409 lg2::error("Polarity field not found for {GPIO_NAME}",
2410 "GPIO_NAME", tempGpioData->lineName);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002411 return -1;
2412 }
Priyatharshan P70120512020-09-16 18:47:20 +05302413 }
2414 else
2415 {
2416 // if dbus based gpio config is defined read and update the dbus
2417 // params corresponding to the gpio config instance
2418 for (auto& [key, dbusParamName] : dbusParams)
2419 {
Logananth Sundararaja4308042021-10-20 11:52:05 +05302420 if (!gpioConfig.contains(dbusParamName))
Priyatharshan P70120512020-09-16 18:47:20 +05302421 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002422 lg2::error(
2423 "The {DBUS_NAME} field must be defined for Dbus configuration ",
2424 "DBUS_NAME", dbusParamName);
Priyatharshan P70120512020-09-16 18:47:20 +05302425 return -1;
2426 }
2427 }
Logananth Sundararaja4308042021-10-20 11:52:05 +05302428 tempGpioData->dbusName =
2429 gpioConfig[dbusParams[DbusConfigType::name]];
2430 tempGpioData->path = gpioConfig[dbusParams[DbusConfigType::path]];
Priyatharshan P70120512020-09-16 18:47:20 +05302431 tempGpioData->interface =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302432 gpioConfig[dbusParams[DbusConfigType::interface]];
Priyatharshan P70120512020-09-16 18:47:20 +05302433 tempGpioData->lineName =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302434 gpioConfig[dbusParams[DbusConfigType::property]];
Priyatharshan P70120512020-09-16 18:47:20 +05302435 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302436 }
2437
Priyatharshan P70120512020-09-16 18:47:20 +05302438 // read and store the timer values from json config to Timer Map
2439 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302440 {
Priyatharshan P70120512020-09-16 18:47:20 +05302441 if (timers.contains(key.c_str()))
2442 {
2443 timerValue = timers[key.c_str()];
2444 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302445 }
2446
Jonathan Doman891bbde2023-05-17 13:58:24 -07002447 // If "events_configs" key is not in json config, fallback to null
2448 auto events = jsonData.value("event_configs",
2449 nlohmann::json(nlohmann::json::value_t::null));
2450 if (events.is_object())
Olivier FAURAXd7ea2832023-04-14 14:08:02 +00002451 {
2452 nmiWhenPoweredOff = events.value("NMIWhenPoweredOff", true);
2453 }
2454
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302455 return 0;
2456}
Zev Weissa8f116a2021-09-01 21:08:30 -05002457
Patrick Williams439b9c32022-07-22 19:26:53 -05002458static bool getDbusMsgGPIOState(sdbusplus::message_t& msg,
Zev Weissa8f116a2021-09-01 21:08:30 -05002459 const std::string& lineName, bool& value)
2460{
2461 std::string thresholdInterface;
2462 std::string event;
2463 boost::container::flat_map<std::string, std::variant<bool>>
2464 propertiesChanged;
2465 try
2466 {
2467 msg.read(thresholdInterface, propertiesChanged);
2468 if (propertiesChanged.empty())
2469 {
2470 return false;
2471 }
2472
2473 event = propertiesChanged.begin()->first;
2474 if (event.empty() || event != lineName)
2475 {
2476 return false;
2477 }
2478
2479 value = std::get<bool>(propertiesChanged.begin()->second);
2480 return true;
2481 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002482 catch (const std::exception& e)
Zev Weissa8f116a2021-09-01 21:08:30 -05002483 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002484 lg2::error(
2485 "exception while reading dbus property \'{DBUS_NAME}\': {ERROR}",
2486 "DBUS_NAME", lineName, "ERROR", e);
Zev Weissa8f116a2021-09-01 21:08:30 -05002487 return false;
2488 }
2489}
2490
Patrick Williams439b9c32022-07-22 19:26:53 -05002491static sdbusplus::bus::match_t
Zev Weissa8f116a2021-09-01 21:08:30 -05002492 dbusGPIOMatcher(const ConfigData& cfg, std::function<void(bool)> onMatch)
2493{
Patrick Williamsd394c882023-10-20 11:18:44 -05002494 auto pulseEventMatcherCallback = [&cfg,
2495 onMatch](sdbusplus::message_t& msg) {
Patrick Williams439b9c32022-07-22 19:26:53 -05002496 bool value = false;
2497 if (!getDbusMsgGPIOState(msg, cfg.lineName, value))
2498 {
2499 return;
2500 }
2501 onMatch(value);
2502 };
Zev Weissa8f116a2021-09-01 21:08:30 -05002503
Patrick Williams439b9c32022-07-22 19:26:53 -05002504 return sdbusplus::bus::match_t(
2505 static_cast<sdbusplus::bus_t&>(*conn),
Zev Weissa8f116a2021-09-01 21:08:30 -05002506 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2507 "PropertiesChanged',arg0='" +
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302508 cfg.interface + "'",
Zev Weissa8f116a2021-09-01 21:08:30 -05002509 std::move(pulseEventMatcherCallback));
2510}
2511
Michal Orzeledd211e2022-10-28 13:10:16 +02002512// D-Bus property read functions
2513void reschedulePropertyRead(const ConfigData& configData);
Priyatharshan P70120512020-09-16 18:47:20 +05302514
Michal Orzeledd211e2022-10-28 13:10:16 +02002515int getProperty(const ConfigData& configData)
2516{
2517 std::variant<bool> resp;
2518
2519 try
Priyatharshan P70120512020-09-16 18:47:20 +05302520 {
Michal Orzeledd211e2022-10-28 13:10:16 +02002521 auto method = conn->new_method_call(
2522 configData.dbusName.c_str(), configData.path.c_str(),
2523 "org.freedesktop.DBus.Properties", "Get");
2524 method.append(configData.interface.c_str(),
2525 configData.lineName.c_str());
2526
2527 auto reply = conn->call(method);
2528 if (reply.is_method_error())
2529 {
2530 lg2::error(
2531 "Error reading {PROPERTY} D-Bus property on interface {INTERFACE} and path {PATH}",
2532 "PROPERTY", configData.lineName, "INTERFACE",
2533 configData.interface, "PATH", configData.path);
2534 return -1;
2535 }
2536
2537 reply.read(resp);
2538 }
2539 catch (const sdbusplus::exception_t& e)
2540 {
2541 lg2::error("Exception while reading {PROPERTY}: {WHAT}", "PROPERTY",
2542 configData.lineName, "WHAT", e.what());
2543 reschedulePropertyRead(configData);
Priyatharshan P70120512020-09-16 18:47:20 +05302544 return -1;
2545 }
Michal Orzeledd211e2022-10-28 13:10:16 +02002546
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302547 auto respValue = std::get_if<bool>(&resp);
Priyatharshan P70120512020-09-16 18:47:20 +05302548 if (!respValue)
2549 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002550 lg2::error("Error: {PROPERTY} D-Bus property is not the expected type",
2551 "PROPERTY", configData.lineName);
Priyatharshan P70120512020-09-16 18:47:20 +05302552 return -1;
2553 }
2554 return (*respValue);
2555}
Michal Orzeledd211e2022-10-28 13:10:16 +02002556
2557void setInitialValue(const ConfigData& configData, bool initialValue)
2558{
2559 if (configData.name == "PowerOk")
2560 {
2561 powerState = (initialValue ? PowerState::on : PowerState::off);
2562 hostIface->set_property("CurrentHostState",
2563 std::string(getHostState(powerState)));
2564 }
2565 else if (configData.name == "PowerButton")
2566 {
2567 powerButtonIface->set_property("ButtonPressed", !initialValue);
2568 }
2569 else if (configData.name == "ResetButton")
2570 {
2571 resetButtonIface->set_property("ButtonPressed", !initialValue);
2572 }
2573 else if (configData.name == "NMIButton")
2574 {
2575 nmiButtonIface->set_property("ButtonPressed", !initialValue);
2576 }
2577 else if (configData.name == "IdButton")
2578 {
2579 idButtonIface->set_property("ButtonPressed", !initialValue);
2580 }
2581 else if (configData.name == "PostComplete")
2582 {
2583 OperatingSystemStateStage osState =
2584 (initialValue ? OperatingSystemStateStage::Inactive
2585 : OperatingSystemStateStage::Standby);
2586 setOperatingSystemState(osState);
2587 }
2588 else
2589 {
2590 lg2::error("Unknown name {NAME}", "NAME", configData.name);
2591 }
2592}
2593
2594void reschedulePropertyRead(const ConfigData& configData)
2595{
2596 auto item = dBusRetryTimers.find(configData.name);
2597
2598 if (item == dBusRetryTimers.end())
2599 {
2600 auto newItem = dBusRetryTimers.insert(
2601 {configData.name, boost::asio::steady_timer(io)});
2602
2603 if (!newItem.second)
2604 {
2605 lg2::error("Failed to add new timer for {NAME}", "NAME",
2606 configData.name);
2607 return;
2608 }
2609
2610 item = newItem.first;
2611 }
2612
2613 auto& timer = item->second;
2614 timer.expires_after(
2615 std::chrono::milliseconds(TimerMap["DbusGetPropertyRetry"]));
2616 timer.async_wait([&configData](const boost::system::error_code ec) {
2617 if (ec)
2618 {
2619 lg2::error("Retry timer for {NAME} failed: {MSG}", "NAME",
2620 configData.name, "MSG", ec.message());
2621 dBusRetryTimers.erase(configData.name);
2622 return;
2623 }
2624
2625 int property = getProperty(configData);
2626
2627 if (property >= 0)
2628 {
2629 setInitialValue(configData, (property > 0));
2630 dBusRetryTimers.erase(configData.name);
2631 }
2632 });
2633}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002634} // namespace power_control
2635
2636int main(int argc, char* argv[])
2637{
Lei YU92caa4c2021-02-23 16:59:25 +08002638 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05302639
2640 if (argc > 1)
2641 {
2642 node = argv[1];
2643 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002644 lg2::info("Start Chassis power control service for host : {NODE}", "NODE",
2645 node);
Priyatharshan P70120512020-09-16 18:47:20 +05302646
Lei YU92caa4c2021-02-23 16:59:25 +08002647 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002648
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302649 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08002650 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302651 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002652 lg2::error("Host{NODE}: Error in Parsing...", "NODE", node);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302653 }
Naveen Mosesec972d82021-07-16 21:19:23 +05302654 /* Currently for single host based systems additional busname is added
2655 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
2656 Going forward for single hosts the old bus name without zero numbering
2657 will be removed when all other applications adapted to the
2658 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
2659
2660 if (node == "0")
2661 {
2662 // Request all the dbus names
2663 conn->request_name(hostDbusName.c_str());
2664 conn->request_name(chassisDbusName.c_str());
2665 conn->request_name(osDbusName.c_str());
2666 conn->request_name(buttonDbusName.c_str());
2667 conn->request_name(nmiDbusName.c_str());
2668 conn->request_name(rstCauseDbusName.c_str());
2669 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302670
Zev Weissc4005bd2021-09-01 22:30:23 -05002671 hostDbusName += node;
2672 chassisDbusName += node;
2673 osDbusName += node;
2674 buttonDbusName += node;
2675 nmiDbusName += node;
2676 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002677
Priyatharshan P70120512020-09-16 18:47:20 +05302678 // Request all the dbus names
2679 conn->request_name(hostDbusName.c_str());
2680 conn->request_name(chassisDbusName.c_str());
2681 conn->request_name(osDbusName.c_str());
2682 conn->request_name(buttonDbusName.c_str());
2683 conn->request_name(nmiDbusName.c_str());
2684 conn->request_name(rstCauseDbusName.c_str());
2685
2686 if (sioPwrGoodConfig.lineName.empty() ||
2687 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05302688 {
Lei YU92caa4c2021-02-23 16:59:25 +08002689 sioEnabled = false;
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002690 lg2::info("SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05302691 }
2692
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002693 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302694 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002695 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002696 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302697 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302698 {
2699 return -1;
2700 }
2701 }
Priyatharshan P70120512020-09-16 18:47:20 +05302702 else if (powerOkConfig.type == ConfigType::DBUS)
2703 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002704 static sdbusplus::bus::match_t powerOkEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002705 power_control::dbusGPIOMatcher(powerOkConfig, psPowerOKHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302706 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302707 else
2708 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002709 lg2::error("PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002710 return -1;
2711 }
2712
Lei YU92caa4c2021-02-23 16:59:25 +08002713 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002714 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05302715 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302716 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302717 {
Priyatharshan P70120512020-09-16 18:47:20 +05302718 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002719 sioPowerGoodHandler, sioPowerGoodLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302720 sioPowerGoodEvent))
2721 {
2722 return -1;
2723 }
2724 }
2725 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
2726 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002727 static sdbusplus::bus::match_t sioPwrGoodEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002728 power_control::dbusGPIOMatcher(sioPwrGoodConfig,
2729 sioPowerGoodHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302730 }
2731 else
2732 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002733 lg2::error(
Priyatharshan P70120512020-09-16 18:47:20 +05302734 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302735 return -1;
2736 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002737
Priyatharshan P19c47a32020-08-12 18:16:43 +05302738 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302739 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302740 {
Priyatharshan P70120512020-09-16 18:47:20 +05302741 if (!requestGPIOEvents(sioOnControlConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002742 sioOnControlHandler, sioOnControlLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302743 sioOnControlEvent))
2744 {
2745 return -1;
2746 }
2747 }
2748 else if (sioOnControlConfig.type == ConfigType::DBUS)
2749 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002750 static sdbusplus::bus::match_t sioOnControlEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002751 power_control::dbusGPIOMatcher(sioOnControlConfig,
2752 sioOnControlHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302753 }
2754 else
2755 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002756 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002757 "sioOnControl name should be configured from jsonconfig file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302758 return -1;
2759 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002760
Priyatharshan P19c47a32020-08-12 18:16:43 +05302761 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302762 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302763 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002764 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
Priyatharshan P70120512020-09-16 18:47:20 +05302765 sioS5Line, sioS5Event))
2766 {
2767 return -1;
2768 }
2769 }
2770 else if (sioS5Config.type == ConfigType::DBUS)
2771 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002772 static sdbusplus::bus::match_t sioS5EventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002773 power_control::dbusGPIOMatcher(sioS5Config, sioS5Handler);
Priyatharshan P70120512020-09-16 18:47:20 +05302774 }
2775 else
2776 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002777 lg2::error("sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302778 return -1;
2779 }
2780 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002781
2782 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302783 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002784 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002785 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
2786 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302787 {
2788 return -1;
2789 }
2790 }
Priyatharshan P70120512020-09-16 18:47:20 +05302791 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302792 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002793 static sdbusplus::bus::match_t powerButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002794 power_control::dbusGPIOMatcher(powerButtonConfig,
2795 powerButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002796 }
2797
2798 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302799 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002800 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002801 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
2802 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302803 {
2804 return -1;
2805 }
2806 }
Priyatharshan P70120512020-09-16 18:47:20 +05302807 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302808 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002809 static sdbusplus::bus::match_t resetButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002810 power_control::dbusGPIOMatcher(resetButtonConfig,
2811 resetButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002812 }
2813
2814 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302815 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302816 {
Priyatharshan P70120512020-09-16 18:47:20 +05302817 if (!nmiButtonConfig.lineName.empty())
2818 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002819 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302820 nmiButtonLine, nmiButtonEvent);
2821 }
2822 }
2823 else if (nmiButtonConfig.type == ConfigType::DBUS)
2824 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002825 static sdbusplus::bus::match_t nmiButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002826 power_control::dbusGPIOMatcher(nmiButtonConfig, nmiButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302827 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002828
2829 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302830 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302831 {
Priyatharshan P70120512020-09-16 18:47:20 +05302832 if (!idButtonConfig.lineName.empty())
2833 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002834 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302835 idButtonLine, idButtonEvent);
2836 }
2837 }
2838 else if (idButtonConfig.type == ConfigType::DBUS)
2839 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002840 static sdbusplus::bus::match_t idButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002841 power_control::dbusGPIOMatcher(idButtonConfig, idButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302842 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002843
Jason M. Billsfb957332021-01-28 13:18:46 -08002844#ifdef USE_PLT_RST
Patrick Williams439b9c32022-07-22 19:26:53 -05002845 sdbusplus::bus::match_t pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08002846 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08002847 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2848 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08002849 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08002850#endif
2851
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002852 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302853 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002854 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002855 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
2856 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302857 {
2858 return -1;
2859 }
2860 }
Priyatharshan P70120512020-09-16 18:47:20 +05302861 else if (postCompleteConfig.type == ConfigType::DBUS)
2862 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002863 static sdbusplus::bus::match_t postCompleteEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002864 power_control::dbusGPIOMatcher(postCompleteConfig,
2865 postCompleteHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302866 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302867 else
2868 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002869 lg2::error(
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002870 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002871 return -1;
2872 }
2873
2874 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05302875 if (!nmiOutConfig.lineName.empty())
2876 {
Jian Zhang461a1662022-09-22 11:29:01 +08002877 setGPIOOutput(nmiOutConfig.lineName, !nmiOutConfig.polarity,
2878 nmiOutLine);
Priyatharshan P70120512020-09-16 18:47:20 +05302879 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002880
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002881 // Initialize POWER_OUT and RESET_OUT GPIO.
2882 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05302883 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002884 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002885 if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
2886 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302887 {
2888 return -1;
2889 }
2890 }
2891 else
2892 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002893 lg2::error("powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002894 return -1;
2895 }
2896
Priyatharshan P70120512020-09-16 18:47:20 +05302897 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002898 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002899 if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
2900 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302901 {
2902 return -1;
2903 }
2904 }
2905 else
2906 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002907 lg2::error("ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002908 return -1;
2909 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002910 // Release line
2911 line.reset();
2912
Matt Simmering58e379d2022-09-23 14:45:50 -07002913 // Initialize the power state and operating system state
Lei YU92caa4c2021-02-23 16:59:25 +08002914 powerState = PowerState::off;
Matt Simmering58e379d2022-09-23 14:45:50 -07002915 operatingSystemState = OperatingSystemStateStage::Inactive;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002916 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05302917
2918 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002919 {
Jean-Marie Verdun61b4a5b2021-09-19 08:53:28 -04002920 if (psPowerOKLine.get_value() > 0 ||
Lei YUa37c2472021-09-26 15:57:12 +08002921 (sioEnabled &&
2922 (sioPowerGoodLine.get_value() == sioPwrGoodConfig.polarity)))
Priyatharshan P70120512020-09-16 18:47:20 +05302923 {
2924 powerState = PowerState::on;
2925 }
2926 }
2927 else
2928 {
2929 if (getProperty(powerOkConfig))
2930 {
2931 powerState = PowerState::on;
2932 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002933 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002934 // Check if we need to start the Power Restore policy
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03002935 if (powerState != PowerState::on)
2936 {
2937 powerRestore.run();
2938 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002939
Lei YU92caa4c2021-02-23 16:59:25 +08002940 if (nmiOutLine)
2941 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002942
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002943 lg2::info("Initializing power state.");
Lei YU92caa4c2021-02-23 16:59:25 +08002944 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002945
2946 // Power Control Service
2947 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002948 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002949
2950 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05302951 hostIface =
2952 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
2953 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002954 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08002955 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002956 "RequestedHostTransition",
2957 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2958 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002959 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2960 {
2961 // if power button is masked, ignore this
2962 if (!powerButtonMask)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002963 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002964 sendPowerControlEvent(Event::gracefulPowerOffRequest);
2965 addRestartCause(RestartCause::command);
Jason M. Billse7520ba2020-01-31 11:19:03 -08002966 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002967 else
2968 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002969 lg2::info("Power Button Masked.");
2970 throw std::invalid_argument("Transition Request Masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002971 return 0;
2972 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05002973 }
2974 else if (requested == "xyz.openbmc_project.State.Host.Transition.On")
2975 {
2976 // if power button is masked, ignore this
2977 if (!powerButtonMask)
2978 {
2979 sendPowerControlEvent(Event::powerOnRequest);
2980 addRestartCause(RestartCause::command);
2981 }
2982 else
2983 {
2984 lg2::info("Power Button Masked.");
2985 throw std::invalid_argument("Transition Request Masked");
2986 return 0;
2987 }
2988 }
2989 else if (requested ==
2990 "xyz.openbmc_project.State.Host.Transition.Reboot")
2991 {
2992 // if power button is masked, ignore this
2993 if (!powerButtonMask)
2994 {
2995 sendPowerControlEvent(Event::powerCycleRequest);
2996 addRestartCause(RestartCause::command);
2997 }
2998 else
2999 {
3000 lg2::info("Power Button Masked.");
3001 throw std::invalid_argument("Transition Request Masked");
3002 return 0;
3003 }
3004 }
3005 else if (requested ==
3006 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot")
3007 {
3008 // if reset button is masked, ignore this
3009 if (!resetButtonMask)
3010 {
3011 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
3012 addRestartCause(RestartCause::command);
3013 }
3014 else
3015 {
3016 lg2::info("Reset Button Masked.");
3017 throw std::invalid_argument("Transition Request Masked");
3018 return 0;
3019 }
3020 }
3021 else if (requested ==
3022 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot")
3023 {
3024 // if reset button is masked, ignore this
3025 if (!resetButtonMask)
3026 {
3027 sendPowerControlEvent(Event::resetRequest);
3028 addRestartCause(RestartCause::command);
3029 }
3030 else
3031 {
3032 lg2::info("Reset Button Masked.");
3033 throw std::invalid_argument("Transition Request Masked");
3034 return 0;
3035 }
3036 }
3037 else
3038 {
3039 lg2::error("Unrecognized host state transition request.");
3040 throw std::invalid_argument("Unrecognized Transition Request");
3041 return 0;
3042 }
3043 resp = requested;
3044 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003045 });
Lei YU92caa4c2021-02-23 16:59:25 +08003046 hostIface->register_property("CurrentHostState",
3047 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003048
Lei YU92caa4c2021-02-23 16:59:25 +08003049 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003050
3051 // Chassis Control Service
3052 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003053 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003054
3055 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003056 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05303057 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003058 "xyz.openbmc_project.State.Chassis");
3059
Lei YU92caa4c2021-02-23 16:59:25 +08003060 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003061 "RequestedPowerTransition",
3062 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
3063 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003064 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
3065 {
3066 // if power button is masked, ignore this
3067 if (!powerButtonMask)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003068 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003069 sendPowerControlEvent(Event::powerOffRequest);
3070 addRestartCause(RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003071 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003072 else
3073 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003074 lg2::info("Power Button Masked.");
3075 throw std::invalid_argument("Transition Request Masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003076 return 0;
3077 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003078 }
3079 else if (requested == "xyz.openbmc_project.State.Chassis.Transition.On")
3080 {
3081 // if power button is masked, ignore this
3082 if (!powerButtonMask)
3083 {
3084 sendPowerControlEvent(Event::powerOnRequest);
3085 addRestartCause(RestartCause::command);
3086 }
3087 else
3088 {
3089 lg2::info("Power Button Masked.");
3090 throw std::invalid_argument("Transition Request Masked");
3091 return 0;
3092 }
3093 }
3094 else if (requested ==
3095 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3096 {
3097 // if power button is masked, ignore this
3098 if (!powerButtonMask)
3099 {
3100 sendPowerControlEvent(Event::powerCycleRequest);
3101 addRestartCause(RestartCause::command);
3102 }
3103 else
3104 {
3105 lg2::info("Power Button Masked.");
3106 throw std::invalid_argument("Transition Request Masked");
3107 return 0;
3108 }
3109 }
3110 else
3111 {
3112 lg2::error("Unrecognized chassis state transition request.");
3113 throw std::invalid_argument("Unrecognized Transition Request");
3114 return 0;
3115 }
3116 resp = requested;
3117 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003118 });
Lei YU92caa4c2021-02-23 16:59:25 +08003119 chassisIface->register_property("CurrentPowerState",
3120 std::string(getChassisState(powerState)));
3121 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003122
Lei YU92caa4c2021-02-23 16:59:25 +08003123 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003124
Vijay Khemka04175c22020-10-09 14:28:11 -07003125#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003126 // Chassis System Service
3127 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003128 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003129
3130 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003131 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003132 "/xyz/openbmc_project/state/chassis_system0",
3133 "xyz.openbmc_project.State.Chassis");
3134
Lei YU92caa4c2021-02-23 16:59:25 +08003135 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003136 "RequestedPowerTransition",
3137 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3138 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003139 if (requested ==
3140 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3141 {
3142 systemReset();
3143 addRestartCause(RestartCause::command);
3144 }
3145 else
3146 {
3147 lg2::error("Unrecognized chassis system state transition request.");
3148 throw std::invalid_argument("Unrecognized Transition Request");
3149 return 0;
3150 }
3151 resp = requested;
3152 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003153 });
Lei YU92caa4c2021-02-23 16:59:25 +08003154 chassisSysIface->register_property(
3155 "CurrentPowerState", std::string(getChassisState(powerState)));
3156 chassisSysIface->register_property("LastStateChangeTime",
3157 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003158
Lei YU92caa4c2021-02-23 16:59:25 +08003159 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003160
Naveen Moses117c34e2021-05-26 20:10:51 +05303161 if (!slotPowerConfig.lineName.empty())
3162 {
3163 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3164 {
3165 return -1;
3166 }
3167
3168 slotPowerState = SlotPowerState::off;
3169 if (slotPowerLine.get_value() > 0)
3170 {
3171 slotPowerState = SlotPowerState::on;
3172 }
3173
3174 chassisSlotIface = chassisSysServer.add_interface(
3175 "/xyz/openbmc_project/state/chassis_system" + node,
3176 "xyz.openbmc_project.State.Chassis");
3177 chassisSlotIface->register_property(
3178 "RequestedPowerTransition",
3179 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3180 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003181 if (requested == "xyz.openbmc_project.State.Chassis.Transition.On")
3182 {
3183 slotPowerOn();
3184 }
3185 else if (requested ==
3186 "xyz.openbmc_project.State.Chassis.Transition.Off")
3187 {
3188 slotPowerOff();
3189 }
3190 else if (requested ==
3191 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3192 {
3193 slotPowerCycle();
3194 }
3195 else
3196 {
3197 lg2::error(
3198 "Unrecognized chassis system state transition request.\n");
3199 throw std::invalid_argument("Unrecognized Transition Request");
3200 return 0;
3201 }
3202 resp = requested;
3203 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003204 });
Naveen Moses117c34e2021-05-26 20:10:51 +05303205 chassisSlotIface->register_property(
3206 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3207 chassisSlotIface->register_property("LastStateChangeTime",
3208 getCurrentTimeMs());
3209 chassisSlotIface->initialize();
3210 }
3211#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003212 // Buttons Service
3213 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003214 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003215
Priyatharshan P70120512020-09-16 18:47:20 +05303216 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003217 {
Priyatharshan P70120512020-09-16 18:47:20 +05303218 // Power Button Interface
3219 power_control::powerButtonIface = buttonsServer.add_interface(
3220 "/xyz/openbmc_project/chassis/buttons/power",
3221 "xyz.openbmc_project.Chassis.Buttons");
3222
3223 powerButtonIface->register_property(
Patrick Williamsd394c882023-10-20 11:18:44 -05003224 "ButtonMasked", false, [](const bool requested, bool& current) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003225 if (requested)
3226 {
3227 if (powerButtonMask)
Priyatharshan P70120512020-09-16 18:47:20 +05303228 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003229 return 1;
Priyatharshan P70120512020-09-16 18:47:20 +05303230 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003231 if (!setGPIOOutput(powerOutConfig.lineName,
3232 !powerOutConfig.polarity, powerButtonMask))
Priyatharshan P70120512020-09-16 18:47:20 +05303233 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003234 throw std::runtime_error("Failed to request GPIO");
3235 return 0;
Priyatharshan P70120512020-09-16 18:47:20 +05303236 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003237 lg2::info("Power Button Masked.");
3238 }
3239 else
3240 {
3241 if (!powerButtonMask)
3242 {
3243 return 1;
3244 }
3245 lg2::info("Power Button Un-masked");
3246 powerButtonMask.reset();
3247 }
3248 // Update the mask setting
3249 current = requested;
3250 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003251 });
Priyatharshan P70120512020-09-16 18:47:20 +05303252
3253 // Check power button state
3254 bool powerButtonPressed;
3255 if (powerButtonConfig.type == ConfigType::GPIO)
3256 {
3257 powerButtonPressed = powerButtonLine.get_value() == 0;
3258 }
3259 else
3260 {
3261 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3262 }
3263
3264 powerButtonIface->register_property("ButtonPressed",
3265 powerButtonPressed);
3266
3267 powerButtonIface->initialize();
3268 }
3269
3270 if (!resetButtonConfig.lineName.empty())
3271 {
3272 // Reset Button Interface
3273
Lei YU92caa4c2021-02-23 16:59:25 +08003274 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003275 "/xyz/openbmc_project/chassis/buttons/reset",
3276 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003277
Lei YU92caa4c2021-02-23 16:59:25 +08003278 resetButtonIface->register_property(
Patrick Williamsd394c882023-10-20 11:18:44 -05003279 "ButtonMasked", false, [](const bool requested, bool& current) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003280 if (requested)
3281 {
3282 if (resetButtonMask)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003283 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003284 return 1;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003285 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003286 if (!setGPIOOutput(resetOutConfig.lineName,
3287 !resetOutConfig.polarity, resetButtonMask))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003288 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003289 throw std::runtime_error("Failed to request GPIO");
3290 return 0;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003291 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003292 lg2::info("Reset Button Masked.");
3293 }
3294 else
3295 {
3296 if (!resetButtonMask)
3297 {
3298 return 1;
3299 }
3300 lg2::info("Reset Button Un-masked");
3301 resetButtonMask.reset();
3302 }
3303 // Update the mask setting
3304 current = requested;
3305 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003306 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003307
John Wang6c090072020-09-30 13:32:16 +08003308 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303309 bool resetButtonPressed;
3310 if (resetButtonConfig.type == ConfigType::GPIO)
3311 {
3312 resetButtonPressed = resetButtonLine.get_value() == 0;
3313 }
3314 else
3315 {
3316 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3317 }
3318
Lei YU92caa4c2021-02-23 16:59:25 +08003319 resetButtonIface->register_property("ButtonPressed",
3320 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003321
Lei YU92caa4c2021-02-23 16:59:25 +08003322 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003323 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003324
Lei YU92caa4c2021-02-23 16:59:25 +08003325 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003326 {
3327 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003328 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003329 "/xyz/openbmc_project/chassis/buttons/nmi",
3330 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003331
Lei YU92caa4c2021-02-23 16:59:25 +08003332 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003333 "ButtonMasked", false, [](const bool requested, bool& current) {
Patrick Williamsd394c882023-10-20 11:18:44 -05003334 if (nmiButtonMasked == requested)
3335 {
3336 // NMI button mask is already set as requested, so no change
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003337 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003338 }
3339 if (requested)
3340 {
3341 lg2::info("NMI Button Masked.");
3342 nmiButtonMasked = true;
3343 }
3344 else
3345 {
3346 lg2::info("NMI Button Un-masked.");
3347 nmiButtonMasked = false;
3348 }
3349 // Update the mask setting
3350 current = nmiButtonMasked;
3351 return 1;
3352 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003353
Vijay Khemka33a532d2019-11-14 16:50:35 -08003354 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303355 bool nmiButtonPressed;
3356 if (nmiButtonConfig.type == ConfigType::GPIO)
3357 {
3358 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3359 }
3360 else
3361 {
3362 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3363 }
3364
Lei YU92caa4c2021-02-23 16:59:25 +08003365 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003366
Lei YU92caa4c2021-02-23 16:59:25 +08003367 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003368 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003369
Lei YU92caa4c2021-02-23 16:59:25 +08003370 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003371 {
3372 // NMI out Service
3373 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003374 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003375
Vijay Khemka33a532d2019-11-14 16:50:35 -08003376 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303377 nmiOutIface = nmiOutServer.add_interface(
3378 "/xyz/openbmc_project/control/host" + node + "/nmi",
3379 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003380 nmiOutIface->register_method("NMI", nmiReset);
3381 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003382 }
Chen Yugang174ec662019-08-19 19:58:49 +08003383
Lei YU92caa4c2021-02-23 16:59:25 +08003384 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003385 {
3386 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003387 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003388 "/xyz/openbmc_project/chassis/buttons/id",
3389 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003390
Vijay Khemka33a532d2019-11-14 16:50:35 -08003391 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303392 bool idButtonPressed;
3393 if (idButtonConfig.type == ConfigType::GPIO)
3394 {
3395 idButtonPressed = idButtonLine.get_value() == 0;
3396 }
3397 else
3398 {
3399 idButtonPressed = getProperty(idButtonConfig) == 0;
3400 }
3401
Lei YU92caa4c2021-02-23 16:59:25 +08003402 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003403
Lei YU92caa4c2021-02-23 16:59:25 +08003404 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003405 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003406
3407 // OS State Service
3408 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003409 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003410
3411 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003412 osIface = osServer.add_interface(
Potin Lai33737912024-02-23 09:53:47 +08003413 "/xyz/openbmc_project/state/host" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003414 "xyz.openbmc_project.State.OperatingSystem.Status");
3415
3416 // Get the initial OS state based on POST complete
3417 // 0: Asserted, OS state is "Standby" (ready to boot)
3418 // 1: De-Asserted, OS state is "Inactive"
Tim Lee86239182021-12-23 11:46:01 +08003419 OperatingSystemStateStage osState;
Priyatharshan P70120512020-09-16 18:47:20 +05303420 if (postCompleteConfig.type == ConfigType::GPIO)
3421 {
Tim Lee86239182021-12-23 11:46:01 +08003422 osState = postCompleteLine.get_value() > 0
3423 ? OperatingSystemStateStage::Inactive
3424 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303425 }
3426 else
3427 {
Tim Lee86239182021-12-23 11:46:01 +08003428 osState = getProperty(postCompleteConfig) > 0
3429 ? OperatingSystemStateStage::Inactive
3430 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303431 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003432
Tim Lee86239182021-12-23 11:46:01 +08003433 osIface->register_property(
3434 "OperatingSystemState",
3435 std::string(getOperatingSystemStateStage(osState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003436
Lei YU92caa4c2021-02-23 16:59:25 +08003437 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003438
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003439 // Restart Cause Service
3440 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003441 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003442
3443 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003444 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303445 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003446 "xyz.openbmc_project.Control.Host.RestartCause");
3447
Lei YU92caa4c2021-02-23 16:59:25 +08003448 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003449 "RestartCause",
3450 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3451
Lei YU92caa4c2021-02-23 16:59:25 +08003452 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003453 "RequestedRestartCause",
3454 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3455 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003456 if (requested ==
3457 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3458 {
3459 addRestartCause(RestartCause::watchdog);
3460 }
3461 else
3462 {
3463 throw std::invalid_argument("Unrecognized RestartCause Request");
3464 return 0;
3465 }
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003466
Patrick Williams48aa1f02023-05-10 07:50:30 -05003467 lg2::info("RestartCause requested: {RESTART_CAUSE}", "RESTART_CAUSE",
3468 requested);
3469 resp = requested;
3470 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003471 });
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003472
Lei YU92caa4c2021-02-23 16:59:25 +08003473 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003474
Lei YU92caa4c2021-02-23 16:59:25 +08003475 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003476
Konstantin Aladyshevcfc4d252021-11-18 11:08:38 +03003477 if (!hpmStbyEnConfig.lineName.empty())
3478 {
3479 // Set to indicate BMC's power control module is ready to take
3480 // the inputs [PWR_GOOD] from the HPM FPGA
3481 gpiod::line hpmLine;
3482 if (!setGPIOOutput(hpmStbyEnConfig.lineName, hpmStbyEnConfig.polarity,
3483 hpmLine))
3484 {
3485 return -1;
3486 }
3487 }
3488
Lei YU92caa4c2021-02-23 16:59:25 +08003489 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003490
3491 return 0;
3492}