blob: 34b3c53fad61bd50e5f98dbadd9e071a7b3600f3 [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{
Patrick Williams48aa1f02023-05-10 07:50:30 -05002017 Event powerControlEvent = state ? Event::psPowerOKAssert
2018 : Event::psPowerOKDeAssert;
Zev Weiss584aa132021-09-02 19:21:52 -05002019 sendPowerControlEvent(powerControlEvent);
2020}
2021
Zev Weiss584aa132021-09-02 19:21:52 -05002022static void sioPowerGoodHandler(bool state)
2023{
Patrick Williams48aa1f02023-05-10 07:50:30 -05002024 Event powerControlEvent = state ? Event::sioPowerGoodAssert
2025 : Event::sioPowerGoodDeAssert;
Zev Weiss584aa132021-09-02 19:21:52 -05002026 sendPowerControlEvent(powerControlEvent);
2027}
2028
Zev Weiss584aa132021-09-02 19:21:52 -05002029static void sioOnControlHandler(bool state)
2030{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002031 lg2::info("SIO_ONCONTROL value changed: {VALUE}", "VALUE",
2032 static_cast<int>(state));
Zev Weiss584aa132021-09-02 19:21:52 -05002033}
2034
Zev Weiss584aa132021-09-02 19:21:52 -05002035static void sioS5Handler(bool state)
2036{
2037 Event powerControlEvent = state ? Event::sioS5DeAssert : Event::sioS5Assert;
2038 sendPowerControlEvent(powerControlEvent);
2039}
2040
Zev Weiss584aa132021-09-02 19:21:52 -05002041static void powerButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002042{
Zev Weiss584aa132021-09-02 19:21:52 -05002043 powerButtonIface->set_property("ButtonPressed", !state);
2044 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002045 {
2046 powerButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002047 if (!powerButtonMask)
2048 {
2049 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002050 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002051 }
2052 else
2053 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002054 lg2::info("power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002055 }
2056 }
Zev Weiss584aa132021-09-02 19:21:52 -05002057}
2058
Zev Weiss584aa132021-09-02 19:21:52 -05002059static void resetButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002060{
Zev Weiss584aa132021-09-02 19:21:52 -05002061 resetButtonIface->set_property("ButtonPressed", !state);
2062 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002063 {
2064 resetButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002065 if (!resetButtonMask)
2066 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002067 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002068 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002069 }
2070 else
2071 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002072 lg2::info("reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002073 }
2074 }
Zev Weiss584aa132021-09-02 19:21:52 -05002075}
2076
Vijay Khemka04175c22020-10-09 14:28:11 -07002077#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002078static constexpr auto systemdBusname = "org.freedesktop.systemd1";
2079static constexpr auto systemdPath = "/org/freedesktop/systemd1";
2080static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
2081static constexpr auto systemTargetName = "chassis-system-reset.target";
2082
2083void systemReset()
2084{
2085 conn->async_method_call(
2086 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002087 if (ec)
2088 {
2089 lg2::error("Failed to call chassis system reset: {ERR}", "ERR",
2090 ec.message());
2091 }
Patrick Williamsd394c882023-10-20 11:18:44 -05002092 },
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002093 systemdBusname, systemdPath, systemdInterface, "StartUnit",
2094 systemTargetName, "replace");
2095}
Vijay Khemka04175c22020-10-09 14:28:11 -07002096#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002097
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002098static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002099{
2100 conn->async_method_call(
2101 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002102 if (ec)
2103 {
2104 lg2::error("failed to set NMI source");
2105 }
Patrick Williamsd394c882023-10-20 11:18:44 -05002106 },
Chen Yugang303bd582019-11-01 08:45:06 +08002107 "xyz.openbmc_project.Settings",
2108 "/xyz/openbmc_project/Chassis/Control/NMISource",
2109 "org.freedesktop.DBus.Properties", "Set",
2110 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
2111 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002112}
2113
2114static void nmiReset(void)
2115{
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002116 const static constexpr int nmiOutPulseTimeMs = 200;
2117
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002118 lg2::info("NMI out action");
Jian Zhang461a1662022-09-22 11:29:01 +08002119 nmiOutLine.set_value(nmiOutConfig.polarity);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002120 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME",
Jian Zhang461a1662022-09-22 11:29:01 +08002121 nmiOutConfig.lineName, "GPIO_VALUE", nmiOutConfig.polarity);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002122 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2123 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2124 // restore the NMI_OUT GPIO line back to the opposite value
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} released", "GPIO_NAME", nmiOutConfig.lineName);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002127 if (ec)
2128 {
2129 // operation_aborted is expected if timer is canceled before
2130 // completion.
2131 if (ec != boost::asio::error::operation_aborted)
2132 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002133 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
2134 "GPIO_NAME", nmiOutConfig.lineName, "ERROR_MSG",
2135 ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002136 }
2137 }
2138 });
2139 // log to redfish
2140 nmiDiagIntLog();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002141 lg2::info("NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002142 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002143 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002144}
2145
2146static void nmiSourcePropertyMonitor(void)
2147{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002148 lg2::info("NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002149
Patrick Williams439b9c32022-07-22 19:26:53 -05002150 static std::unique_ptr<sdbusplus::bus::match_t> nmiSourceMatch =
2151 std::make_unique<sdbusplus::bus::match_t>(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002152 *conn,
2153 "type='signal',interface='org.freedesktop.DBus.Properties',"
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002154 "member='PropertiesChanged',"
2155 "arg0namespace='xyz.openbmc_project.Chassis.Control.NMISource'",
Patrick Williams439b9c32022-07-22 19:26:53 -05002156 [](sdbusplus::message_t& msg) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002157 std::string interfaceName;
2158 boost::container::flat_map<std::string, std::variant<bool, std::string>>
2159 propertiesChanged;
2160 std::string state;
2161 bool value = true;
2162 try
2163 {
2164 msg.read(interfaceName, propertiesChanged);
2165 if (propertiesChanged.begin()->first == "Enabled")
2166 {
2167 value = std::get<bool>(propertiesChanged.begin()->second);
2168 lg2::info("NMI Enabled propertiesChanged value: {VALUE}",
2169 "VALUE", value);
2170 nmiEnabled = value;
2171 if (nmiEnabled)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002172 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002173 nmiReset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002174 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05002175 }
2176 }
2177 catch (const std::exception& e)
2178 {
2179 lg2::error("Unable to read NMI source: {ERROR}", "ERROR", e);
2180 return;
2181 }
Patrick Williamsd394c882023-10-20 11:18:44 -05002182 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002183}
2184
2185static void setNmiSource()
2186{
2187 conn->async_method_call(
2188 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002189 if (ec)
2190 {
2191 lg2::error("failed to set NMI source");
2192 }
Patrick Williamsd394c882023-10-20 11:18:44 -05002193 },
Chen Yugang303bd582019-11-01 08:45:06 +08002194 "xyz.openbmc_project.Settings",
2195 "/xyz/openbmc_project/Chassis/Control/NMISource",
2196 "org.freedesktop.DBus.Properties", "Set",
2197 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
Jason M. Bills418ce112021-09-08 15:15:05 -07002198 std::variant<std::string>{
2199 "xyz.openbmc_project.Chassis.Control.NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002200 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002201 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002202}
2203
Zev Weiss584aa132021-09-02 19:21:52 -05002204static void nmiButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002205{
Olivier FAURAXd7ea2832023-04-14 14:08:02 +00002206 // Don't handle event if host not running and config doesn't force it
2207 if (!nmiWhenPoweredOff &&
2208 getHostState(powerState) !=
2209 "xyz.openbmc_project.State.Host.HostState.Running")
2210 {
2211 return;
2212 }
Zev Weiss584aa132021-09-02 19:21:52 -05002213 nmiButtonIface->set_property("ButtonPressed", !state);
2214 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002215 {
2216 nmiButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002217 if (nmiButtonMasked)
2218 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002219 lg2::info("NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002220 }
2221 else
2222 {
2223 setNmiSource();
2224 }
2225 }
Zev Weiss584aa132021-09-02 19:21:52 -05002226}
2227
Zev Weiss584aa132021-09-02 19:21:52 -05002228static void idButtonHandler(bool state)
2229{
2230 idButtonIface->set_property("ButtonPressed", !state);
2231}
2232
Jason M. Billsfb957332021-01-28 13:18:46 -08002233static void pltRstHandler(bool pltRst)
2234{
2235 if (pltRst)
2236 {
2237 sendPowerControlEvent(Event::pltRstDeAssert);
2238 }
2239 else
2240 {
2241 sendPowerControlEvent(Event::pltRstAssert);
2242 }
2243}
2244
Patrick Williams439b9c32022-07-22 19:26:53 -05002245[[maybe_unused]] static void hostMiscHandler(sdbusplus::message_t& msg)
Jason M. Billsfb957332021-01-28 13:18:46 -08002246{
2247 std::string interfaceName;
2248 boost::container::flat_map<std::string, std::variant<bool>>
2249 propertiesChanged;
Jason M. Billsfb957332021-01-28 13:18:46 -08002250 try
2251 {
2252 msg.read(interfaceName, propertiesChanged);
2253 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002254 catch (const std::exception& e)
Jason M. Billsfb957332021-01-28 13:18:46 -08002255 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002256 lg2::error("Unable to read Host Misc status: {ERROR}", "ERROR", e);
Jason M. Billsfb957332021-01-28 13:18:46 -08002257 return;
2258 }
2259 if (propertiesChanged.empty())
2260 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002261 lg2::error("ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002262 return;
2263 }
2264
2265 for (auto& [property, value] : propertiesChanged)
2266 {
2267 if (property == "ESpiPlatformReset")
2268 {
2269 bool* pltRst = std::get_if<bool>(&value);
2270 if (pltRst == nullptr)
2271 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002272 lg2::error("{PROPERTY} property invalid", "PROPERTY", property);
Jason M. Billsfb957332021-01-28 13:18:46 -08002273 return;
2274 }
2275 pltRstHandler(*pltRst);
2276 }
2277 }
2278}
2279
Zev Weiss584aa132021-09-02 19:21:52 -05002280static void postCompleteHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002281{
Zev Weiss584aa132021-09-02 19:21:52 -05002282 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002283 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002284 sendPowerControlEvent(Event::postCompleteAssert);
Tim Lee86239182021-12-23 11:46:01 +08002285 setOperatingSystemState(OperatingSystemStateStage::Standby);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002286 }
2287 else
2288 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002289 sendPowerControlEvent(Event::postCompleteDeAssert);
Tim Lee86239182021-12-23 11:46:01 +08002290 setOperatingSystemState(OperatingSystemStateStage::Inactive);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002291 }
Zev Weiss584aa132021-09-02 19:21:52 -05002292}
2293
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302294static int loadConfigValues()
2295{
2296 const std::string configFilePath =
2297 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2298 ".json";
2299 std::ifstream configFile(configFilePath.c_str());
2300 if (!configFile.is_open())
2301 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002302 lg2::error("loadConfigValues: Cannot open config path \'{PATH}\'",
2303 "PATH", configFilePath);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302304 return -1;
2305 }
Zev Weiss1aa08b22021-09-15 17:06:20 -05002306 auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302307
Priyatharshan P70120512020-09-16 18:47:20 +05302308 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302309 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002310 lg2::error("Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302311 return -1;
2312 }
Priyatharshan P70120512020-09-16 18:47:20 +05302313 auto gpios = jsonData["gpio_configs"];
2314 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302315
Priyatharshan P70120512020-09-16 18:47:20 +05302316 ConfigData* tempGpioData;
2317
2318 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302319 {
Priyatharshan P70120512020-09-16 18:47:20 +05302320 if (!gpioConfig.contains("Name"))
2321 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002322 lg2::error("The 'Name' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302323 return -1;
2324 }
2325
2326 // Iterate through the powersignal map to check if the gpio json config
2327 // entry is valid
2328 std::string gpioName = gpioConfig["Name"];
2329 auto signalMapIter = powerSignalMap.find(gpioName);
2330 if (signalMapIter == powerSignalMap.end())
2331 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002332 lg2::error(
2333 "{GPIO_NAME} is not a recognized power-control signal name",
2334 "GPIO_NAME", gpioName);
Priyatharshan P70120512020-09-16 18:47:20 +05302335 return -1;
2336 }
2337
2338 // assign the power signal name to the corresponding structure reference
2339 // from map then fillup the structure with coressponding json config
2340 // value
2341 tempGpioData = signalMapIter->second;
2342 tempGpioData->name = gpioName;
2343
2344 if (!gpioConfig.contains("Type"))
2345 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002346 lg2::error("The \'Type\' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302347 return -1;
2348 }
2349
2350 std::string signalType = gpioConfig["Type"];
2351 if (signalType == "GPIO")
2352 {
2353 tempGpioData->type = ConfigType::GPIO;
2354 }
2355 else if (signalType == "DBUS")
2356 {
2357 tempGpioData->type = ConfigType::DBUS;
2358 }
2359 else
2360 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002361 lg2::error("{TYPE} is not a recognized power-control signal type",
2362 "TYPE", signalType);
Priyatharshan P70120512020-09-16 18:47:20 +05302363 return -1;
2364 }
2365
2366 if (tempGpioData->type == ConfigType::GPIO)
2367 {
2368 if (gpioConfig.contains("LineName"))
2369 {
2370 tempGpioData->lineName = gpioConfig["LineName"];
2371 }
2372 else
2373 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002374 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002375 "The \'LineName\' field must be defined for GPIO configuration");
Priyatharshan P70120512020-09-16 18:47:20 +05302376 return -1;
2377 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002378 if (gpioConfig.contains("Polarity"))
2379 {
2380 std::string polarity = gpioConfig["Polarity"];
2381 if (polarity == "ActiveLow")
2382 {
2383 tempGpioData->polarity = false;
2384 }
2385 else if (polarity == "ActiveHigh")
2386 {
2387 tempGpioData->polarity = true;
2388 }
2389 else
2390 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002391 lg2::error(
2392 "Polarity defined but not properly setup. Please only ActiveHigh or ActiveLow. Currently set to {POLARITY}",
2393 "POLARITY", polarity);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002394 return -1;
2395 }
2396 }
2397 else
2398 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002399 lg2::error("Polarity field not found for {GPIO_NAME}",
2400 "GPIO_NAME", tempGpioData->lineName);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002401 return -1;
2402 }
Priyatharshan P70120512020-09-16 18:47:20 +05302403 }
2404 else
2405 {
2406 // if dbus based gpio config is defined read and update the dbus
2407 // params corresponding to the gpio config instance
2408 for (auto& [key, dbusParamName] : dbusParams)
2409 {
Logananth Sundararaja4308042021-10-20 11:52:05 +05302410 if (!gpioConfig.contains(dbusParamName))
Priyatharshan P70120512020-09-16 18:47:20 +05302411 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002412 lg2::error(
2413 "The {DBUS_NAME} field must be defined for Dbus configuration ",
2414 "DBUS_NAME", dbusParamName);
Priyatharshan P70120512020-09-16 18:47:20 +05302415 return -1;
2416 }
2417 }
Logananth Sundararaja4308042021-10-20 11:52:05 +05302418 tempGpioData->dbusName =
2419 gpioConfig[dbusParams[DbusConfigType::name]];
2420 tempGpioData->path = gpioConfig[dbusParams[DbusConfigType::path]];
Priyatharshan P70120512020-09-16 18:47:20 +05302421 tempGpioData->interface =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302422 gpioConfig[dbusParams[DbusConfigType::interface]];
Priyatharshan P70120512020-09-16 18:47:20 +05302423 tempGpioData->lineName =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302424 gpioConfig[dbusParams[DbusConfigType::property]];
Priyatharshan P70120512020-09-16 18:47:20 +05302425 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302426 }
2427
Priyatharshan P70120512020-09-16 18:47:20 +05302428 // read and store the timer values from json config to Timer Map
2429 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302430 {
Priyatharshan P70120512020-09-16 18:47:20 +05302431 if (timers.contains(key.c_str()))
2432 {
2433 timerValue = timers[key.c_str()];
2434 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302435 }
2436
Jonathan Doman891bbde2023-05-17 13:58:24 -07002437 // If "events_configs" key is not in json config, fallback to null
2438 auto events = jsonData.value("event_configs",
2439 nlohmann::json(nlohmann::json::value_t::null));
2440 if (events.is_object())
Olivier FAURAXd7ea2832023-04-14 14:08:02 +00002441 {
2442 nmiWhenPoweredOff = events.value("NMIWhenPoweredOff", true);
2443 }
2444
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302445 return 0;
2446}
Zev Weissa8f116a2021-09-01 21:08:30 -05002447
Patrick Williams439b9c32022-07-22 19:26:53 -05002448static bool getDbusMsgGPIOState(sdbusplus::message_t& msg,
Zev Weissa8f116a2021-09-01 21:08:30 -05002449 const std::string& lineName, bool& value)
2450{
2451 std::string thresholdInterface;
2452 std::string event;
2453 boost::container::flat_map<std::string, std::variant<bool>>
2454 propertiesChanged;
2455 try
2456 {
2457 msg.read(thresholdInterface, propertiesChanged);
2458 if (propertiesChanged.empty())
2459 {
2460 return false;
2461 }
2462
2463 event = propertiesChanged.begin()->first;
2464 if (event.empty() || event != lineName)
2465 {
2466 return false;
2467 }
2468
2469 value = std::get<bool>(propertiesChanged.begin()->second);
2470 return true;
2471 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002472 catch (const std::exception& e)
Zev Weissa8f116a2021-09-01 21:08:30 -05002473 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002474 lg2::error(
2475 "exception while reading dbus property \'{DBUS_NAME}\': {ERROR}",
2476 "DBUS_NAME", lineName, "ERROR", e);
Zev Weissa8f116a2021-09-01 21:08:30 -05002477 return false;
2478 }
2479}
2480
Patrick Williams439b9c32022-07-22 19:26:53 -05002481static sdbusplus::bus::match_t
Zev Weissa8f116a2021-09-01 21:08:30 -05002482 dbusGPIOMatcher(const ConfigData& cfg, std::function<void(bool)> onMatch)
2483{
Patrick Williamsd394c882023-10-20 11:18:44 -05002484 auto pulseEventMatcherCallback = [&cfg,
2485 onMatch](sdbusplus::message_t& msg) {
Patrick Williams439b9c32022-07-22 19:26:53 -05002486 bool value = false;
2487 if (!getDbusMsgGPIOState(msg, cfg.lineName, value))
2488 {
2489 return;
2490 }
2491 onMatch(value);
2492 };
Zev Weissa8f116a2021-09-01 21:08:30 -05002493
Patrick Williams439b9c32022-07-22 19:26:53 -05002494 return sdbusplus::bus::match_t(
2495 static_cast<sdbusplus::bus_t&>(*conn),
Zev Weissa8f116a2021-09-01 21:08:30 -05002496 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2497 "PropertiesChanged',arg0='" +
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302498 cfg.interface + "'",
Zev Weissa8f116a2021-09-01 21:08:30 -05002499 std::move(pulseEventMatcherCallback));
2500}
2501
Michal Orzeledd211e2022-10-28 13:10:16 +02002502// D-Bus property read functions
2503void reschedulePropertyRead(const ConfigData& configData);
Priyatharshan P70120512020-09-16 18:47:20 +05302504
Michal Orzeledd211e2022-10-28 13:10:16 +02002505int getProperty(const ConfigData& configData)
2506{
2507 std::variant<bool> resp;
2508
2509 try
Priyatharshan P70120512020-09-16 18:47:20 +05302510 {
Michal Orzeledd211e2022-10-28 13:10:16 +02002511 auto method = conn->new_method_call(
2512 configData.dbusName.c_str(), configData.path.c_str(),
2513 "org.freedesktop.DBus.Properties", "Get");
2514 method.append(configData.interface.c_str(),
2515 configData.lineName.c_str());
2516
2517 auto reply = conn->call(method);
2518 if (reply.is_method_error())
2519 {
2520 lg2::error(
2521 "Error reading {PROPERTY} D-Bus property on interface {INTERFACE} and path {PATH}",
2522 "PROPERTY", configData.lineName, "INTERFACE",
2523 configData.interface, "PATH", configData.path);
2524 return -1;
2525 }
2526
2527 reply.read(resp);
2528 }
2529 catch (const sdbusplus::exception_t& e)
2530 {
2531 lg2::error("Exception while reading {PROPERTY}: {WHAT}", "PROPERTY",
2532 configData.lineName, "WHAT", e.what());
2533 reschedulePropertyRead(configData);
Priyatharshan P70120512020-09-16 18:47:20 +05302534 return -1;
2535 }
Michal Orzeledd211e2022-10-28 13:10:16 +02002536
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302537 auto respValue = std::get_if<bool>(&resp);
Priyatharshan P70120512020-09-16 18:47:20 +05302538 if (!respValue)
2539 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002540 lg2::error("Error: {PROPERTY} D-Bus property is not the expected type",
2541 "PROPERTY", configData.lineName);
Priyatharshan P70120512020-09-16 18:47:20 +05302542 return -1;
2543 }
2544 return (*respValue);
2545}
Michal Orzeledd211e2022-10-28 13:10:16 +02002546
2547void setInitialValue(const ConfigData& configData, bool initialValue)
2548{
2549 if (configData.name == "PowerOk")
2550 {
2551 powerState = (initialValue ? PowerState::on : PowerState::off);
2552 hostIface->set_property("CurrentHostState",
2553 std::string(getHostState(powerState)));
2554 }
2555 else if (configData.name == "PowerButton")
2556 {
2557 powerButtonIface->set_property("ButtonPressed", !initialValue);
2558 }
2559 else if (configData.name == "ResetButton")
2560 {
2561 resetButtonIface->set_property("ButtonPressed", !initialValue);
2562 }
2563 else if (configData.name == "NMIButton")
2564 {
2565 nmiButtonIface->set_property("ButtonPressed", !initialValue);
2566 }
2567 else if (configData.name == "IdButton")
2568 {
2569 idButtonIface->set_property("ButtonPressed", !initialValue);
2570 }
2571 else if (configData.name == "PostComplete")
2572 {
2573 OperatingSystemStateStage osState =
2574 (initialValue ? OperatingSystemStateStage::Inactive
2575 : OperatingSystemStateStage::Standby);
2576 setOperatingSystemState(osState);
2577 }
2578 else
2579 {
2580 lg2::error("Unknown name {NAME}", "NAME", configData.name);
2581 }
2582}
2583
2584void reschedulePropertyRead(const ConfigData& configData)
2585{
2586 auto item = dBusRetryTimers.find(configData.name);
2587
2588 if (item == dBusRetryTimers.end())
2589 {
2590 auto newItem = dBusRetryTimers.insert(
2591 {configData.name, boost::asio::steady_timer(io)});
2592
2593 if (!newItem.second)
2594 {
2595 lg2::error("Failed to add new timer for {NAME}", "NAME",
2596 configData.name);
2597 return;
2598 }
2599
2600 item = newItem.first;
2601 }
2602
2603 auto& timer = item->second;
2604 timer.expires_after(
2605 std::chrono::milliseconds(TimerMap["DbusGetPropertyRetry"]));
2606 timer.async_wait([&configData](const boost::system::error_code ec) {
2607 if (ec)
2608 {
2609 lg2::error("Retry timer for {NAME} failed: {MSG}", "NAME",
2610 configData.name, "MSG", ec.message());
2611 dBusRetryTimers.erase(configData.name);
2612 return;
2613 }
2614
2615 int property = getProperty(configData);
2616
2617 if (property >= 0)
2618 {
2619 setInitialValue(configData, (property > 0));
2620 dBusRetryTimers.erase(configData.name);
2621 }
2622 });
2623}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002624} // namespace power_control
2625
2626int main(int argc, char* argv[])
2627{
Lei YU92caa4c2021-02-23 16:59:25 +08002628 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05302629
2630 if (argc > 1)
2631 {
2632 node = argv[1];
2633 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002634 lg2::info("Start Chassis power control service for host : {NODE}", "NODE",
2635 node);
Priyatharshan P70120512020-09-16 18:47:20 +05302636
Lei YU92caa4c2021-02-23 16:59:25 +08002637 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002638
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302639 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08002640 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302641 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002642 lg2::error("Host{NODE}: Error in Parsing...", "NODE", node);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302643 }
Naveen Mosesec972d82021-07-16 21:19:23 +05302644 /* Currently for single host based systems additional busname is added
2645 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
2646 Going forward for single hosts the old bus name without zero numbering
2647 will be removed when all other applications adapted to the
2648 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
2649
2650 if (node == "0")
2651 {
2652 // Request all the dbus names
2653 conn->request_name(hostDbusName.c_str());
2654 conn->request_name(chassisDbusName.c_str());
2655 conn->request_name(osDbusName.c_str());
2656 conn->request_name(buttonDbusName.c_str());
2657 conn->request_name(nmiDbusName.c_str());
2658 conn->request_name(rstCauseDbusName.c_str());
2659 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302660
Zev Weissc4005bd2021-09-01 22:30:23 -05002661 hostDbusName += node;
2662 chassisDbusName += node;
2663 osDbusName += node;
2664 buttonDbusName += node;
2665 nmiDbusName += node;
2666 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002667
Priyatharshan P70120512020-09-16 18:47:20 +05302668 // Request all the dbus names
2669 conn->request_name(hostDbusName.c_str());
2670 conn->request_name(chassisDbusName.c_str());
2671 conn->request_name(osDbusName.c_str());
2672 conn->request_name(buttonDbusName.c_str());
2673 conn->request_name(nmiDbusName.c_str());
2674 conn->request_name(rstCauseDbusName.c_str());
2675
2676 if (sioPwrGoodConfig.lineName.empty() ||
2677 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05302678 {
Lei YU92caa4c2021-02-23 16:59:25 +08002679 sioEnabled = false;
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002680 lg2::info("SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05302681 }
2682
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002683 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302684 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002685 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002686 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302687 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302688 {
2689 return -1;
2690 }
2691 }
Priyatharshan P70120512020-09-16 18:47:20 +05302692 else if (powerOkConfig.type == ConfigType::DBUS)
2693 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002694 static sdbusplus::bus::match_t powerOkEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002695 power_control::dbusGPIOMatcher(powerOkConfig, psPowerOKHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302696 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302697 else
2698 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002699 lg2::error("PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002700 return -1;
2701 }
2702
Lei YU92caa4c2021-02-23 16:59:25 +08002703 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002704 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05302705 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302706 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302707 {
Priyatharshan P70120512020-09-16 18:47:20 +05302708 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002709 sioPowerGoodHandler, sioPowerGoodLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302710 sioPowerGoodEvent))
2711 {
2712 return -1;
2713 }
2714 }
2715 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
2716 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002717 static sdbusplus::bus::match_t sioPwrGoodEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002718 power_control::dbusGPIOMatcher(sioPwrGoodConfig,
2719 sioPowerGoodHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302720 }
2721 else
2722 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002723 lg2::error(
Priyatharshan P70120512020-09-16 18:47:20 +05302724 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302725 return -1;
2726 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002727
Priyatharshan P19c47a32020-08-12 18:16:43 +05302728 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302729 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302730 {
Priyatharshan P70120512020-09-16 18:47:20 +05302731 if (!requestGPIOEvents(sioOnControlConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002732 sioOnControlHandler, sioOnControlLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302733 sioOnControlEvent))
2734 {
2735 return -1;
2736 }
2737 }
2738 else if (sioOnControlConfig.type == ConfigType::DBUS)
2739 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002740 static sdbusplus::bus::match_t sioOnControlEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002741 power_control::dbusGPIOMatcher(sioOnControlConfig,
2742 sioOnControlHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302743 }
2744 else
2745 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002746 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002747 "sioOnControl name should be configured from jsonconfig file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302748 return -1;
2749 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002750
Priyatharshan P19c47a32020-08-12 18:16:43 +05302751 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302752 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302753 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002754 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
Priyatharshan P70120512020-09-16 18:47:20 +05302755 sioS5Line, sioS5Event))
2756 {
2757 return -1;
2758 }
2759 }
2760 else if (sioS5Config.type == ConfigType::DBUS)
2761 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002762 static sdbusplus::bus::match_t sioS5EventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002763 power_control::dbusGPIOMatcher(sioS5Config, sioS5Handler);
Priyatharshan P70120512020-09-16 18:47:20 +05302764 }
2765 else
2766 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002767 lg2::error("sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302768 return -1;
2769 }
2770 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002771
2772 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302773 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002774 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002775 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
2776 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302777 {
2778 return -1;
2779 }
2780 }
Priyatharshan P70120512020-09-16 18:47:20 +05302781 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302782 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002783 static sdbusplus::bus::match_t powerButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002784 power_control::dbusGPIOMatcher(powerButtonConfig,
2785 powerButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002786 }
2787
2788 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302789 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002790 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002791 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
2792 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302793 {
2794 return -1;
2795 }
2796 }
Priyatharshan P70120512020-09-16 18:47:20 +05302797 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302798 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002799 static sdbusplus::bus::match_t resetButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002800 power_control::dbusGPIOMatcher(resetButtonConfig,
2801 resetButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002802 }
2803
2804 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302805 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302806 {
Priyatharshan P70120512020-09-16 18:47:20 +05302807 if (!nmiButtonConfig.lineName.empty())
2808 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002809 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302810 nmiButtonLine, nmiButtonEvent);
2811 }
2812 }
2813 else if (nmiButtonConfig.type == ConfigType::DBUS)
2814 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002815 static sdbusplus::bus::match_t nmiButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002816 power_control::dbusGPIOMatcher(nmiButtonConfig, nmiButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302817 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002818
2819 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302820 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302821 {
Priyatharshan P70120512020-09-16 18:47:20 +05302822 if (!idButtonConfig.lineName.empty())
2823 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002824 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302825 idButtonLine, idButtonEvent);
2826 }
2827 }
2828 else if (idButtonConfig.type == ConfigType::DBUS)
2829 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002830 static sdbusplus::bus::match_t idButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002831 power_control::dbusGPIOMatcher(idButtonConfig, idButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302832 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002833
Jason M. Billsfb957332021-01-28 13:18:46 -08002834#ifdef USE_PLT_RST
Patrick Williams439b9c32022-07-22 19:26:53 -05002835 sdbusplus::bus::match_t pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08002836 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08002837 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2838 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08002839 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08002840#endif
2841
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002842 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302843 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002844 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002845 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
2846 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302847 {
2848 return -1;
2849 }
2850 }
Priyatharshan P70120512020-09-16 18:47:20 +05302851 else if (postCompleteConfig.type == ConfigType::DBUS)
2852 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002853 static sdbusplus::bus::match_t postCompleteEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002854 power_control::dbusGPIOMatcher(postCompleteConfig,
2855 postCompleteHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302856 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302857 else
2858 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002859 lg2::error(
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002860 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002861 return -1;
2862 }
2863
2864 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05302865 if (!nmiOutConfig.lineName.empty())
2866 {
Jian Zhang461a1662022-09-22 11:29:01 +08002867 setGPIOOutput(nmiOutConfig.lineName, !nmiOutConfig.polarity,
2868 nmiOutLine);
Priyatharshan P70120512020-09-16 18:47:20 +05302869 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002870
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002871 // Initialize POWER_OUT and RESET_OUT GPIO.
2872 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05302873 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002874 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002875 if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
2876 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302877 {
2878 return -1;
2879 }
2880 }
2881 else
2882 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002883 lg2::error("powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002884 return -1;
2885 }
2886
Priyatharshan P70120512020-09-16 18:47:20 +05302887 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002888 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002889 if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
2890 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302891 {
2892 return -1;
2893 }
2894 }
2895 else
2896 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002897 lg2::error("ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002898 return -1;
2899 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002900 // Release line
2901 line.reset();
2902
Matt Simmering58e379d2022-09-23 14:45:50 -07002903 // Initialize the power state and operating system state
Lei YU92caa4c2021-02-23 16:59:25 +08002904 powerState = PowerState::off;
Matt Simmering58e379d2022-09-23 14:45:50 -07002905 operatingSystemState = OperatingSystemStateStage::Inactive;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002906 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05302907
2908 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002909 {
Jean-Marie Verdun61b4a5b2021-09-19 08:53:28 -04002910 if (psPowerOKLine.get_value() > 0 ||
Lei YUa37c2472021-09-26 15:57:12 +08002911 (sioEnabled &&
2912 (sioPowerGoodLine.get_value() == sioPwrGoodConfig.polarity)))
Priyatharshan P70120512020-09-16 18:47:20 +05302913 {
2914 powerState = PowerState::on;
2915 }
2916 }
2917 else
2918 {
2919 if (getProperty(powerOkConfig))
2920 {
2921 powerState = PowerState::on;
2922 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002923 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002924 // Check if we need to start the Power Restore policy
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03002925 if (powerState != PowerState::on)
2926 {
2927 powerRestore.run();
2928 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002929
Lei YU92caa4c2021-02-23 16:59:25 +08002930 if (nmiOutLine)
2931 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002932
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002933 lg2::info("Initializing power state.");
Lei YU92caa4c2021-02-23 16:59:25 +08002934 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002935
2936 // Power Control Service
2937 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002938 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002939
2940 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05302941 hostIface =
2942 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
2943 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002944 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08002945 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002946 "RequestedHostTransition",
2947 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2948 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002949 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2950 {
2951 // if power button is masked, ignore this
2952 if (!powerButtonMask)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002953 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002954 sendPowerControlEvent(Event::gracefulPowerOffRequest);
2955 addRestartCause(RestartCause::command);
Jason M. Billse7520ba2020-01-31 11:19:03 -08002956 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002957 else
2958 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002959 lg2::info("Power Button Masked.");
2960 throw std::invalid_argument("Transition Request Masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002961 return 0;
2962 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05002963 }
2964 else if (requested == "xyz.openbmc_project.State.Host.Transition.On")
2965 {
2966 // if power button is masked, ignore this
2967 if (!powerButtonMask)
2968 {
2969 sendPowerControlEvent(Event::powerOnRequest);
2970 addRestartCause(RestartCause::command);
2971 }
2972 else
2973 {
2974 lg2::info("Power Button Masked.");
2975 throw std::invalid_argument("Transition Request Masked");
2976 return 0;
2977 }
2978 }
2979 else if (requested ==
2980 "xyz.openbmc_project.State.Host.Transition.Reboot")
2981 {
2982 // if power button is masked, ignore this
2983 if (!powerButtonMask)
2984 {
2985 sendPowerControlEvent(Event::powerCycleRequest);
2986 addRestartCause(RestartCause::command);
2987 }
2988 else
2989 {
2990 lg2::info("Power Button Masked.");
2991 throw std::invalid_argument("Transition Request Masked");
2992 return 0;
2993 }
2994 }
2995 else if (requested ==
2996 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot")
2997 {
2998 // if reset button is masked, ignore this
2999 if (!resetButtonMask)
3000 {
3001 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
3002 addRestartCause(RestartCause::command);
3003 }
3004 else
3005 {
3006 lg2::info("Reset Button Masked.");
3007 throw std::invalid_argument("Transition Request Masked");
3008 return 0;
3009 }
3010 }
3011 else if (requested ==
3012 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot")
3013 {
3014 // if reset button is masked, ignore this
3015 if (!resetButtonMask)
3016 {
3017 sendPowerControlEvent(Event::resetRequest);
3018 addRestartCause(RestartCause::command);
3019 }
3020 else
3021 {
3022 lg2::info("Reset Button Masked.");
3023 throw std::invalid_argument("Transition Request Masked");
3024 return 0;
3025 }
3026 }
3027 else
3028 {
3029 lg2::error("Unrecognized host state transition request.");
3030 throw std::invalid_argument("Unrecognized Transition Request");
3031 return 0;
3032 }
3033 resp = requested;
3034 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003035 });
Lei YU92caa4c2021-02-23 16:59:25 +08003036 hostIface->register_property("CurrentHostState",
3037 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003038
Lei YU92caa4c2021-02-23 16:59:25 +08003039 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003040
3041 // Chassis Control Service
3042 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003043 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003044
3045 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003046 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05303047 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003048 "xyz.openbmc_project.State.Chassis");
3049
Lei YU92caa4c2021-02-23 16:59:25 +08003050 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003051 "RequestedPowerTransition",
3052 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
3053 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003054 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
3055 {
3056 // if power button is masked, ignore this
3057 if (!powerButtonMask)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003058 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003059 sendPowerControlEvent(Event::powerOffRequest);
3060 addRestartCause(RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003061 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003062 else
3063 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003064 lg2::info("Power Button Masked.");
3065 throw std::invalid_argument("Transition Request Masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003066 return 0;
3067 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003068 }
3069 else if (requested == "xyz.openbmc_project.State.Chassis.Transition.On")
3070 {
3071 // if power button is masked, ignore this
3072 if (!powerButtonMask)
3073 {
3074 sendPowerControlEvent(Event::powerOnRequest);
3075 addRestartCause(RestartCause::command);
3076 }
3077 else
3078 {
3079 lg2::info("Power Button Masked.");
3080 throw std::invalid_argument("Transition Request Masked");
3081 return 0;
3082 }
3083 }
3084 else if (requested ==
3085 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3086 {
3087 // if power button is masked, ignore this
3088 if (!powerButtonMask)
3089 {
3090 sendPowerControlEvent(Event::powerCycleRequest);
3091 addRestartCause(RestartCause::command);
3092 }
3093 else
3094 {
3095 lg2::info("Power Button Masked.");
3096 throw std::invalid_argument("Transition Request Masked");
3097 return 0;
3098 }
3099 }
3100 else
3101 {
3102 lg2::error("Unrecognized chassis state transition request.");
3103 throw std::invalid_argument("Unrecognized Transition Request");
3104 return 0;
3105 }
3106 resp = requested;
3107 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003108 });
Lei YU92caa4c2021-02-23 16:59:25 +08003109 chassisIface->register_property("CurrentPowerState",
3110 std::string(getChassisState(powerState)));
3111 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003112
Lei YU92caa4c2021-02-23 16:59:25 +08003113 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003114
Vijay Khemka04175c22020-10-09 14:28:11 -07003115#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003116 // Chassis System Service
3117 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003118 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003119
3120 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003121 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003122 "/xyz/openbmc_project/state/chassis_system0",
3123 "xyz.openbmc_project.State.Chassis");
3124
Lei YU92caa4c2021-02-23 16:59:25 +08003125 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003126 "RequestedPowerTransition",
3127 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3128 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003129 if (requested ==
3130 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3131 {
3132 systemReset();
3133 addRestartCause(RestartCause::command);
3134 }
3135 else
3136 {
3137 lg2::error("Unrecognized chassis system state transition request.");
3138 throw std::invalid_argument("Unrecognized Transition Request");
3139 return 0;
3140 }
3141 resp = requested;
3142 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003143 });
Lei YU92caa4c2021-02-23 16:59:25 +08003144 chassisSysIface->register_property(
3145 "CurrentPowerState", std::string(getChassisState(powerState)));
3146 chassisSysIface->register_property("LastStateChangeTime",
3147 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003148
Lei YU92caa4c2021-02-23 16:59:25 +08003149 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003150
Naveen Moses117c34e2021-05-26 20:10:51 +05303151 if (!slotPowerConfig.lineName.empty())
3152 {
3153 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3154 {
3155 return -1;
3156 }
3157
3158 slotPowerState = SlotPowerState::off;
3159 if (slotPowerLine.get_value() > 0)
3160 {
3161 slotPowerState = SlotPowerState::on;
3162 }
3163
3164 chassisSlotIface = chassisSysServer.add_interface(
3165 "/xyz/openbmc_project/state/chassis_system" + node,
3166 "xyz.openbmc_project.State.Chassis");
3167 chassisSlotIface->register_property(
3168 "RequestedPowerTransition",
3169 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3170 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003171 if (requested == "xyz.openbmc_project.State.Chassis.Transition.On")
3172 {
3173 slotPowerOn();
3174 }
3175 else if (requested ==
3176 "xyz.openbmc_project.State.Chassis.Transition.Off")
3177 {
3178 slotPowerOff();
3179 }
3180 else if (requested ==
3181 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3182 {
3183 slotPowerCycle();
3184 }
3185 else
3186 {
3187 lg2::error(
3188 "Unrecognized chassis system state transition request.\n");
3189 throw std::invalid_argument("Unrecognized Transition Request");
3190 return 0;
3191 }
3192 resp = requested;
3193 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003194 });
Naveen Moses117c34e2021-05-26 20:10:51 +05303195 chassisSlotIface->register_property(
3196 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3197 chassisSlotIface->register_property("LastStateChangeTime",
3198 getCurrentTimeMs());
3199 chassisSlotIface->initialize();
3200 }
3201#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003202 // Buttons Service
3203 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003204 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003205
Priyatharshan P70120512020-09-16 18:47:20 +05303206 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003207 {
Priyatharshan P70120512020-09-16 18:47:20 +05303208 // Power Button Interface
3209 power_control::powerButtonIface = buttonsServer.add_interface(
3210 "/xyz/openbmc_project/chassis/buttons/power",
3211 "xyz.openbmc_project.Chassis.Buttons");
3212
3213 powerButtonIface->register_property(
Patrick Williamsd394c882023-10-20 11:18:44 -05003214 "ButtonMasked", false, [](const bool requested, bool& current) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003215 if (requested)
3216 {
3217 if (powerButtonMask)
Priyatharshan P70120512020-09-16 18:47:20 +05303218 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003219 return 1;
Priyatharshan P70120512020-09-16 18:47:20 +05303220 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003221 if (!setGPIOOutput(powerOutConfig.lineName,
3222 !powerOutConfig.polarity, powerButtonMask))
Priyatharshan P70120512020-09-16 18:47:20 +05303223 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003224 throw std::runtime_error("Failed to request GPIO");
3225 return 0;
Priyatharshan P70120512020-09-16 18:47:20 +05303226 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003227 lg2::info("Power Button Masked.");
3228 }
3229 else
3230 {
3231 if (!powerButtonMask)
3232 {
3233 return 1;
3234 }
3235 lg2::info("Power Button Un-masked");
3236 powerButtonMask.reset();
3237 }
3238 // Update the mask setting
3239 current = requested;
3240 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003241 });
Priyatharshan P70120512020-09-16 18:47:20 +05303242
3243 // Check power button state
3244 bool powerButtonPressed;
3245 if (powerButtonConfig.type == ConfigType::GPIO)
3246 {
3247 powerButtonPressed = powerButtonLine.get_value() == 0;
3248 }
3249 else
3250 {
3251 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3252 }
3253
3254 powerButtonIface->register_property("ButtonPressed",
3255 powerButtonPressed);
3256
3257 powerButtonIface->initialize();
3258 }
3259
3260 if (!resetButtonConfig.lineName.empty())
3261 {
3262 // Reset Button Interface
3263
Lei YU92caa4c2021-02-23 16:59:25 +08003264 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003265 "/xyz/openbmc_project/chassis/buttons/reset",
3266 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003267
Lei YU92caa4c2021-02-23 16:59:25 +08003268 resetButtonIface->register_property(
Patrick Williamsd394c882023-10-20 11:18:44 -05003269 "ButtonMasked", false, [](const bool requested, bool& current) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003270 if (requested)
3271 {
3272 if (resetButtonMask)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003273 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003274 return 1;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003275 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003276 if (!setGPIOOutput(resetOutConfig.lineName,
3277 !resetOutConfig.polarity, resetButtonMask))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003278 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003279 throw std::runtime_error("Failed to request GPIO");
3280 return 0;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003281 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003282 lg2::info("Reset Button Masked.");
3283 }
3284 else
3285 {
3286 if (!resetButtonMask)
3287 {
3288 return 1;
3289 }
3290 lg2::info("Reset Button Un-masked");
3291 resetButtonMask.reset();
3292 }
3293 // Update the mask setting
3294 current = requested;
3295 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003296 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003297
John Wang6c090072020-09-30 13:32:16 +08003298 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303299 bool resetButtonPressed;
3300 if (resetButtonConfig.type == ConfigType::GPIO)
3301 {
3302 resetButtonPressed = resetButtonLine.get_value() == 0;
3303 }
3304 else
3305 {
3306 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3307 }
3308
Lei YU92caa4c2021-02-23 16:59:25 +08003309 resetButtonIface->register_property("ButtonPressed",
3310 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003311
Lei YU92caa4c2021-02-23 16:59:25 +08003312 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003313 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003314
Lei YU92caa4c2021-02-23 16:59:25 +08003315 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003316 {
3317 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003318 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003319 "/xyz/openbmc_project/chassis/buttons/nmi",
3320 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003321
Lei YU92caa4c2021-02-23 16:59:25 +08003322 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003323 "ButtonMasked", false, [](const bool requested, bool& current) {
Patrick Williamsd394c882023-10-20 11:18:44 -05003324 if (nmiButtonMasked == requested)
3325 {
3326 // NMI button mask is already set as requested, so no change
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003327 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003328 }
3329 if (requested)
3330 {
3331 lg2::info("NMI Button Masked.");
3332 nmiButtonMasked = true;
3333 }
3334 else
3335 {
3336 lg2::info("NMI Button Un-masked.");
3337 nmiButtonMasked = false;
3338 }
3339 // Update the mask setting
3340 current = nmiButtonMasked;
3341 return 1;
3342 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003343
Vijay Khemka33a532d2019-11-14 16:50:35 -08003344 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303345 bool nmiButtonPressed;
3346 if (nmiButtonConfig.type == ConfigType::GPIO)
3347 {
3348 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3349 }
3350 else
3351 {
3352 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3353 }
3354
Lei YU92caa4c2021-02-23 16:59:25 +08003355 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003356
Lei YU92caa4c2021-02-23 16:59:25 +08003357 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003358 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003359
Lei YU92caa4c2021-02-23 16:59:25 +08003360 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003361 {
3362 // NMI out Service
3363 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003364 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003365
Vijay Khemka33a532d2019-11-14 16:50:35 -08003366 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303367 nmiOutIface = nmiOutServer.add_interface(
3368 "/xyz/openbmc_project/control/host" + node + "/nmi",
3369 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003370 nmiOutIface->register_method("NMI", nmiReset);
3371 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003372 }
Chen Yugang174ec662019-08-19 19:58:49 +08003373
Lei YU92caa4c2021-02-23 16:59:25 +08003374 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003375 {
3376 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003377 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003378 "/xyz/openbmc_project/chassis/buttons/id",
3379 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003380
Vijay Khemka33a532d2019-11-14 16:50:35 -08003381 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303382 bool idButtonPressed;
3383 if (idButtonConfig.type == ConfigType::GPIO)
3384 {
3385 idButtonPressed = idButtonLine.get_value() == 0;
3386 }
3387 else
3388 {
3389 idButtonPressed = getProperty(idButtonConfig) == 0;
3390 }
3391
Lei YU92caa4c2021-02-23 16:59:25 +08003392 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003393
Lei YU92caa4c2021-02-23 16:59:25 +08003394 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003395 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003396
3397 // OS State Service
3398 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003399 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003400
3401 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003402 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003403 "/xyz/openbmc_project/state/os",
3404 "xyz.openbmc_project.State.OperatingSystem.Status");
3405
3406 // Get the initial OS state based on POST complete
3407 // 0: Asserted, OS state is "Standby" (ready to boot)
3408 // 1: De-Asserted, OS state is "Inactive"
Tim Lee86239182021-12-23 11:46:01 +08003409 OperatingSystemStateStage osState;
Priyatharshan P70120512020-09-16 18:47:20 +05303410 if (postCompleteConfig.type == ConfigType::GPIO)
3411 {
Tim Lee86239182021-12-23 11:46:01 +08003412 osState = postCompleteLine.get_value() > 0
3413 ? OperatingSystemStateStage::Inactive
3414 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303415 }
3416 else
3417 {
Tim Lee86239182021-12-23 11:46:01 +08003418 osState = getProperty(postCompleteConfig) > 0
3419 ? OperatingSystemStateStage::Inactive
3420 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303421 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003422
Tim Lee86239182021-12-23 11:46:01 +08003423 osIface->register_property(
3424 "OperatingSystemState",
3425 std::string(getOperatingSystemStateStage(osState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003426
Lei YU92caa4c2021-02-23 16:59:25 +08003427 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003428
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003429 // Restart Cause Service
3430 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003431 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003432
3433 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003434 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303435 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003436 "xyz.openbmc_project.Control.Host.RestartCause");
3437
Lei YU92caa4c2021-02-23 16:59:25 +08003438 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003439 "RestartCause",
3440 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3441
Lei YU92caa4c2021-02-23 16:59:25 +08003442 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003443 "RequestedRestartCause",
3444 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3445 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003446 if (requested ==
3447 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3448 {
3449 addRestartCause(RestartCause::watchdog);
3450 }
3451 else
3452 {
3453 throw std::invalid_argument("Unrecognized RestartCause Request");
3454 return 0;
3455 }
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003456
Patrick Williams48aa1f02023-05-10 07:50:30 -05003457 lg2::info("RestartCause requested: {RESTART_CAUSE}", "RESTART_CAUSE",
3458 requested);
3459 resp = requested;
3460 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003461 });
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003462
Lei YU92caa4c2021-02-23 16:59:25 +08003463 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003464
Lei YU92caa4c2021-02-23 16:59:25 +08003465 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003466
Konstantin Aladyshevcfc4d252021-11-18 11:08:38 +03003467 if (!hpmStbyEnConfig.lineName.empty())
3468 {
3469 // Set to indicate BMC's power control module is ready to take
3470 // the inputs [PWR_GOOD] from the HPM FPGA
3471 gpiod::line hpmLine;
3472 if (!setGPIOOutput(hpmStbyEnConfig.lineName, hpmStbyEnConfig.polarity,
3473 hpmLine))
3474 {
3475 return -1;
3476 }
3477 }
3478
Lei YU92caa4c2021-02-23 16:59:25 +08003479 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003480
3481 return 0;
3482}