blob: 22574844ebc36b20ecea61ae68884f1538ea3b2d [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;
88
Priyatharshan P70120512020-09-16 18:47:20 +053089// map for storing list of gpio parameters whose config are to be read from x86
90// power control json config
91boost::container::flat_map<std::string, ConfigData*> powerSignalMap = {
92 {"PowerOut", &powerOutConfig},
93 {"PowerOk", &powerOkConfig},
94 {"ResetOut", &resetOutConfig},
95 {"NMIOut", &nmiOutConfig},
96 {"SioPowerGood", &sioPwrGoodConfig},
97 {"SioOnControl", &sioOnControlConfig},
98 {"SIOS5", &sioS5Config},
99 {"PostComplete", &postCompleteConfig},
100 {"PowerButton", &powerButtonConfig},
101 {"ResetButton", &resetButtonConfig},
102 {"IdButton", &idButtonConfig},
Naveen Moses117c34e2021-05-26 20:10:51 +0530103 {"NMIButton", &nmiButtonConfig},
104 {"SlotPower", &slotPowerConfig}};
Priyatharshan P70120512020-09-16 18:47:20 +0530105
106static std::string hostDbusName = "xyz.openbmc_project.State.Host";
107static std::string chassisDbusName = "xyz.openbmc_project.State.Chassis";
108static std::string osDbusName = "xyz.openbmc_project.State.OperatingSystem";
109static std::string buttonDbusName = "xyz.openbmc_project.Chassis.Buttons";
110static std::string nmiDbusName = "xyz.openbmc_project.Control.Host.NMI";
111static std::string rstCauseDbusName =
112 "xyz.openbmc_project.Control.Host.RestartCause";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700113static std::shared_ptr<sdbusplus::asio::dbus_interface> hostIface;
114static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700115#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -0700116static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSysIface;
Naveen Moses117c34e2021-05-26 20:10:51 +0530117static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSlotIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700118#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700119static std::shared_ptr<sdbusplus::asio::dbus_interface> powerButtonIface;
120static std::shared_ptr<sdbusplus::asio::dbus_interface> resetButtonIface;
121static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiButtonIface;
122static std::shared_ptr<sdbusplus::asio::dbus_interface> osIface;
123static std::shared_ptr<sdbusplus::asio::dbus_interface> idButtonIface;
Chen Yugang174ec662019-08-19 19:58:49 +0800124static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiOutIface;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700125static std::shared_ptr<sdbusplus::asio::dbus_interface> restartCauseIface;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700126
127static gpiod::line powerButtonMask;
128static gpiod::line resetButtonMask;
129static bool nmiButtonMasked = false;
Matt Simmering58e379d2022-09-23 14:45:50 -0700130#if IGNORE_SOFT_RESETS_DURING_POST
131static bool ignoreNextSoftReset = false;
132#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700133
Priyatharshan P70120512020-09-16 18:47:20 +0530134// This map contains all timer values that are to be read from json config
135boost::container::flat_map<std::string, int> TimerMap = {
Jason M. Billsaeefe042021-09-08 14:56:11 -0700136 {"PowerPulseMs", 200},
137 {"ForceOffPulseMs", 15000},
138 {"ResetPulseMs", 500},
139 {"PowerCycleMs", 5000},
140 {"SioPowerGoodWatchdogMs", 1000},
141 {"PsPowerOKWatchdogMs", 8000},
142 {"GracefulPowerOffS", (5 * 60)},
143 {"WarmResetCheckMs", 500},
144 {"PowerOffSaveMs", 7000},
Michal Orzeledd211e2022-10-28 13:10:16 +0200145 {"SlotPowerCycleMs", 200},
146 {"DbusGetPropertyRetry", 1000}};
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700147
148static bool nmiEnabled = true;
Olivier FAURAXd7ea2832023-04-14 14:08:02 +0000149static bool nmiWhenPoweredOff = true;
Priyatharshan P19c47a32020-08-12 18:16:43 +0530150static bool sioEnabled = true;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700151
152// Timers
153// Time holding GPIOs asserted
154static boost::asio::steady_timer gpioAssertTimer(io);
155// Time between off and on during a power cycle
156static boost::asio::steady_timer powerCycleTimer(io);
157// Time OS gracefully powering off
158static boost::asio::steady_timer gracefulPowerOffTimer(io);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700159// Time the warm reset check
160static boost::asio::steady_timer warmResetCheckTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700161// Time power supply power OK assertion on power-on
162static boost::asio::steady_timer psPowerOKWatchdogTimer(io);
163// Time SIO power good assertion on power-on
164static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io);
165// Time power-off state save for power loss tracking
166static boost::asio::steady_timer powerStateSaveTimer(io);
167// POH timer
168static boost::asio::steady_timer pohCounterTimer(io);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700169// Time when to allow restart cause updates
170static boost::asio::steady_timer restartCauseTimer(io);
Naveen Moses117c34e2021-05-26 20:10:51 +0530171static boost::asio::steady_timer slotPowerCycleTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700172
Michal Orzeledd211e2022-10-28 13:10:16 +0200173// Map containing timers used for D-Bus get-property retries
174static boost::container::flat_map<std::string, boost::asio::steady_timer>
175 dBusRetryTimers;
176
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700177// GPIO Lines and Event Descriptors
178static gpiod::line psPowerOKLine;
179static boost::asio::posix::stream_descriptor psPowerOKEvent(io);
180static gpiod::line sioPowerGoodLine;
181static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io);
182static gpiod::line sioOnControlLine;
183static boost::asio::posix::stream_descriptor sioOnControlEvent(io);
184static gpiod::line sioS5Line;
185static boost::asio::posix::stream_descriptor sioS5Event(io);
186static gpiod::line powerButtonLine;
187static boost::asio::posix::stream_descriptor powerButtonEvent(io);
188static gpiod::line resetButtonLine;
189static boost::asio::posix::stream_descriptor resetButtonEvent(io);
190static gpiod::line nmiButtonLine;
191static boost::asio::posix::stream_descriptor nmiButtonEvent(io);
192static gpiod::line idButtonLine;
193static boost::asio::posix::stream_descriptor idButtonEvent(io);
194static gpiod::line postCompleteLine;
195static boost::asio::posix::stream_descriptor postCompleteEvent(io);
196static gpiod::line nmiOutLine;
Naveen Moses117c34e2021-05-26 20:10:51 +0530197static gpiod::line slotPowerLine;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700198
199static constexpr uint8_t beepPowerFail = 8;
200
201static void beep(const uint8_t& beepPriority)
202{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800203 lg2::info("Beep with priority: {BEEP_PRIORITY}", "BEEP_PRIORITY",
204 beepPriority);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700205
206 conn->async_method_call(
207 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -0500208 if (ec)
209 {
210 lg2::error(
211 "beep returned error with async_method_call (ec = {ERROR_MSG})",
212 "ERROR_MSG", ec.message());
213 return;
214 }
Patrick Williamsd394c882023-10-20 11:18:44 -0500215 },
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700216 "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
217 "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
218}
219
Tim Lee86239182021-12-23 11:46:01 +0800220enum class OperatingSystemStateStage
221{
222 Inactive,
223 Standby,
224};
Matt Simmering58e379d2022-09-23 14:45:50 -0700225static OperatingSystemStateStage operatingSystemState;
Tim Lee86239182021-12-23 11:46:01 +0800226static constexpr std::string_view
227 getOperatingSystemStateStage(const OperatingSystemStateStage stage)
228{
229 switch (stage)
230 {
231 case OperatingSystemStateStage::Inactive:
232 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
233 break;
234 case OperatingSystemStateStage::Standby:
235 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Standby";
236 break;
237 default:
238 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
239 break;
240 }
241};
242static void setOperatingSystemState(const OperatingSystemStateStage stage)
243{
Matt Simmering58e379d2022-09-23 14:45:50 -0700244 operatingSystemState = stage;
245#if IGNORE_SOFT_RESETS_DURING_POST
246 // If POST complete has asserted set ignoreNextSoftReset to false to avoid
247 // masking soft resets after POST
248 if (operatingSystemState == OperatingSystemStateStage::Standby)
249 {
250 ignoreNextSoftReset = false;
251 }
252#endif
Tim Lee86239182021-12-23 11:46:01 +0800253 osIface->set_property("OperatingSystemState",
254 std::string(getOperatingSystemStateStage(stage)));
255
256 lg2::info("Moving os state to {STATE} stage", "STATE",
257 getOperatingSystemStateStage(stage));
258}
259
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700260enum class PowerState
261{
262 on,
263 waitForPSPowerOK,
264 waitForSIOPowerGood,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700265 off,
266 transitionToOff,
267 gracefulTransitionToOff,
268 cycleOff,
269 transitionToCycleOff,
270 gracefulTransitionToCycleOff,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700271 checkForWarmReset,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700272};
273static PowerState powerState;
274static std::string getPowerStateName(PowerState state)
275{
276 switch (state)
277 {
278 case PowerState::on:
279 return "On";
280 break;
281 case PowerState::waitForPSPowerOK:
282 return "Wait for Power Supply Power OK";
283 break;
284 case PowerState::waitForSIOPowerGood:
285 return "Wait for SIO Power Good";
286 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700287 case PowerState::off:
288 return "Off";
289 break;
290 case PowerState::transitionToOff:
291 return "Transition to Off";
292 break;
293 case PowerState::gracefulTransitionToOff:
294 return "Graceful Transition to Off";
295 break;
296 case PowerState::cycleOff:
297 return "Power Cycle Off";
298 break;
299 case PowerState::transitionToCycleOff:
300 return "Transition to Power Cycle Off";
301 break;
302 case PowerState::gracefulTransitionToCycleOff:
303 return "Graceful Transition to Power Cycle Off";
304 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700305 case PowerState::checkForWarmReset:
306 return "Check for Warm Reset";
307 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700308 default:
309 return "unknown state: " + std::to_string(static_cast<int>(state));
310 break;
311 }
312}
313static void logStateTransition(const PowerState state)
314{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800315 lg2::info("Host{HOST}: Moving to \"{STATE}\" state", "HOST", node, "STATE",
316 getPowerStateName(state));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700317}
318
319enum class Event
320{
321 psPowerOKAssert,
322 psPowerOKDeAssert,
323 sioPowerGoodAssert,
324 sioPowerGoodDeAssert,
325 sioS5Assert,
326 sioS5DeAssert,
Jason M. Billsfb957332021-01-28 13:18:46 -0800327 pltRstAssert,
328 pltRstDeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700329 postCompleteAssert,
330 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700331 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700332 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700333 powerCycleTimerExpired,
334 psPowerOKWatchdogTimerExpired,
335 sioPowerGoodWatchdogTimerExpired,
336 gracefulPowerOffTimerExpired,
337 powerOnRequest,
338 powerOffRequest,
339 powerCycleRequest,
340 resetRequest,
341 gracefulPowerOffRequest,
342 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700343 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700344};
345static std::string getEventName(Event event)
346{
347 switch (event)
348 {
349 case Event::psPowerOKAssert:
350 return "power supply power OK assert";
351 break;
352 case Event::psPowerOKDeAssert:
353 return "power supply power OK de-assert";
354 break;
355 case Event::sioPowerGoodAssert:
356 return "SIO power good assert";
357 break;
358 case Event::sioPowerGoodDeAssert:
359 return "SIO power good de-assert";
360 break;
361 case Event::sioS5Assert:
362 return "SIO S5 assert";
363 break;
364 case Event::sioS5DeAssert:
365 return "SIO S5 de-assert";
366 break;
Jason M. Billsfb957332021-01-28 13:18:46 -0800367 case Event::pltRstAssert:
368 return "PLT_RST assert";
369 break;
370 case Event::pltRstDeAssert:
371 return "PLT_RST de-assert";
372 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700373 case Event::postCompleteAssert:
374 return "POST Complete assert";
375 break;
376 case Event::postCompleteDeAssert:
377 return "POST Complete de-assert";
378 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700379 case Event::powerButtonPressed:
380 return "power button pressed";
381 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700382 case Event::resetButtonPressed:
383 return "reset button pressed";
384 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700385 case Event::powerCycleTimerExpired:
386 return "power cycle timer expired";
387 break;
388 case Event::psPowerOKWatchdogTimerExpired:
389 return "power supply power OK watchdog timer expired";
390 break;
391 case Event::sioPowerGoodWatchdogTimerExpired:
392 return "SIO power good watchdog timer expired";
393 break;
394 case Event::gracefulPowerOffTimerExpired:
395 return "graceful power-off timer expired";
396 break;
397 case Event::powerOnRequest:
398 return "power-on request";
399 break;
400 case Event::powerOffRequest:
401 return "power-off request";
402 break;
403 case Event::powerCycleRequest:
404 return "power-cycle request";
405 break;
406 case Event::resetRequest:
407 return "reset request";
408 break;
409 case Event::gracefulPowerOffRequest:
410 return "graceful power-off request";
411 break;
412 case Event::gracefulPowerCycleRequest:
413 return "graceful power-cycle request";
414 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700415 case Event::warmResetDetected:
416 return "warm reset detected";
417 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700418 default:
419 return "unknown event: " + std::to_string(static_cast<int>(event));
420 break;
421 }
422}
423static void logEvent(const std::string_view stateHandler, const Event event)
424{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800425 lg2::info("{STATE_HANDLER}: {EVENT} event received", "STATE_HANDLER",
426 stateHandler, "EVENT", getEventName(event));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700427}
428
429// Power state handlers
430static void powerStateOn(const Event event);
431static void powerStateWaitForPSPowerOK(const Event event);
432static void powerStateWaitForSIOPowerGood(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700433static void powerStateOff(const Event event);
434static void powerStateTransitionToOff(const Event event);
435static void powerStateGracefulTransitionToOff(const Event event);
436static void powerStateCycleOff(const Event event);
437static void powerStateTransitionToCycleOff(const Event event);
438static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700439static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700440
441static std::function<void(const Event)> getPowerStateHandler(PowerState state)
442{
443 switch (state)
444 {
445 case PowerState::on:
446 return powerStateOn;
447 break;
448 case PowerState::waitForPSPowerOK:
449 return powerStateWaitForPSPowerOK;
450 break;
451 case PowerState::waitForSIOPowerGood:
452 return powerStateWaitForSIOPowerGood;
453 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700454 case PowerState::off:
455 return powerStateOff;
456 break;
457 case PowerState::transitionToOff:
458 return powerStateTransitionToOff;
459 break;
460 case PowerState::gracefulTransitionToOff:
461 return powerStateGracefulTransitionToOff;
462 break;
463 case PowerState::cycleOff:
464 return powerStateCycleOff;
465 break;
466 case PowerState::transitionToCycleOff:
467 return powerStateTransitionToCycleOff;
468 break;
469 case PowerState::gracefulTransitionToCycleOff:
470 return powerStateGracefulTransitionToCycleOff;
471 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700472 case PowerState::checkForWarmReset:
473 return powerStateCheckForWarmReset;
474 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700475 default:
Zev Weiss047bcb52020-08-20 21:28:11 +0000476 return nullptr;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700477 break;
478 }
479};
480
481static void sendPowerControlEvent(const Event event)
482{
483 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
484 if (handler == nullptr)
485 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800486 lg2::error("Failed to find handler for power state: {STATE}", "STATE",
487 static_cast<int>(powerState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700488 return;
489 }
490 handler(event);
491}
492
493static uint64_t getCurrentTimeMs()
494{
495 struct timespec time = {};
496
497 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
498 {
499 return 0;
500 }
501 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
502 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
503
504 return currentTimeMs;
505}
506
507static constexpr std::string_view getHostState(const PowerState state)
508{
509 switch (state)
510 {
511 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700512 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700513 case PowerState::gracefulTransitionToCycleOff:
514 return "xyz.openbmc_project.State.Host.HostState.Running";
515 break;
516 case PowerState::waitForPSPowerOK:
517 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700518 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700519 case PowerState::transitionToOff:
520 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700521 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700522 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700523 return "xyz.openbmc_project.State.Host.HostState.Off";
524 break;
525 default:
526 return "";
527 break;
528 }
529};
530static constexpr std::string_view getChassisState(const PowerState state)
531{
532 switch (state)
533 {
534 case PowerState::on:
535 case PowerState::transitionToOff:
536 case PowerState::gracefulTransitionToOff:
537 case PowerState::transitionToCycleOff:
538 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700539 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700540 return "xyz.openbmc_project.State.Chassis.PowerState.On";
541 break;
542 case PowerState::waitForPSPowerOK:
543 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700544 case PowerState::off:
545 case PowerState::cycleOff:
546 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
547 break;
548 default:
549 return "";
550 break;
551 }
552};
Naveen Moses117c34e2021-05-26 20:10:51 +0530553#ifdef CHASSIS_SYSTEM_RESET
554enum class SlotPowerState
555{
556 on,
557 off,
558};
559static SlotPowerState slotPowerState;
560static constexpr std::string_view getSlotState(const SlotPowerState state)
561{
562 switch (state)
563 {
564 case SlotPowerState::on:
565 return "xyz.openbmc_project.State.Chassis.PowerState.On";
566 break;
567 case SlotPowerState::off:
568 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
569 break;
570 default:
571 return "";
572 break;
573 }
574};
575static void setSlotPowerState(const SlotPowerState state)
576{
577 slotPowerState = state;
578 chassisSlotIface->set_property("CurrentPowerState",
579 std::string(getSlotState(slotPowerState)));
580 chassisSlotIface->set_property("LastStateChangeTime", getCurrentTimeMs());
581}
582#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700583static void savePowerState(const PowerState state)
584{
585 powerStateSaveTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -0700586 std::chrono::milliseconds(TimerMap["PowerOffSaveMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700587 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
588 if (ec)
589 {
590 // operation_aborted is expected if timer is canceled before
591 // completion.
592 if (ec != boost::asio::error::operation_aborted)
593 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800594 lg2::error("Power-state save async_wait failed: {ERROR_MSG}",
595 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700596 }
597 return;
598 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300599 appState.set(PersistentState::Params::PowerState,
600 std::string{getChassisState(state)});
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700601 });
602}
603static void setPowerState(const PowerState state)
604{
605 powerState = state;
606 logStateTransition(state);
607
608 hostIface->set_property("CurrentHostState",
609 std::string(getHostState(powerState)));
610
611 chassisIface->set_property("CurrentPowerState",
612 std::string(getChassisState(powerState)));
613 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
614
615 // Save the power state for the restore policy
616 savePowerState(state);
617}
618
619enum class RestartCause
620{
621 command,
622 resetButton,
623 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700624 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700625 powerPolicyOn,
626 powerPolicyRestore,
627 softReset,
628};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700629static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700630static std::string getRestartCause(RestartCause cause)
631{
632 switch (cause)
633 {
634 case RestartCause::command:
635 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
636 break;
637 case RestartCause::resetButton:
638 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
639 break;
640 case RestartCause::powerButton:
641 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
642 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700643 case RestartCause::watchdog:
644 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
645 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700646 case RestartCause::powerPolicyOn:
Jason M. Bills418ce112021-09-08 15:15:05 -0700647 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyAlwaysOn";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700648 break;
649 case RestartCause::powerPolicyRestore:
Jason M. Bills418ce112021-09-08 15:15:05 -0700650 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyPreviousState";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700651 break;
652 case RestartCause::softReset:
653 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
654 break;
655 default:
656 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
657 break;
658 }
659}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700660static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700661{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700662 // Add this to the set of causes for this restart
663 causeSet.insert(cause);
664}
665static void clearRestartCause()
666{
667 // Clear the set for the next restart
668 causeSet.clear();
669}
670static void setRestartCauseProperty(const std::string& cause)
671{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800672 lg2::info("RestartCause set to {RESTART_CAUSE}", "RESTART_CAUSE", cause);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700673 restartCauseIface->set_property("RestartCause", cause);
674}
Rashmi RV89f61312020-01-22 15:41:50 +0530675
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300676#ifdef USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +0530677static void resetACBootProperty()
678{
679 if ((causeSet.contains(RestartCause::command)) ||
680 (causeSet.contains(RestartCause::softReset)))
681 {
682 conn->async_method_call(
683 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -0500684 if (ec)
685 {
686 lg2::error("failed to reset ACBoot property");
687 }
Patrick Williamsd394c882023-10-20 11:18:44 -0500688 },
Rashmi RV89f61312020-01-22 15:41:50 +0530689 "xyz.openbmc_project.Settings",
690 "/xyz/openbmc_project/control/host0/ac_boot",
691 "org.freedesktop.DBus.Properties", "Set",
692 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
693 std::variant<std::string>{"False"});
694 }
695}
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300696#endif // USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +0530697
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700698static void setRestartCause()
699{
700 // Determine the actual restart cause based on the set of causes
701 std::string restartCause =
702 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
703 if (causeSet.contains(RestartCause::watchdog))
704 {
705 restartCause = getRestartCause(RestartCause::watchdog);
706 }
707 else if (causeSet.contains(RestartCause::command))
708 {
709 restartCause = getRestartCause(RestartCause::command);
710 }
711 else if (causeSet.contains(RestartCause::resetButton))
712 {
713 restartCause = getRestartCause(RestartCause::resetButton);
714 }
715 else if (causeSet.contains(RestartCause::powerButton))
716 {
717 restartCause = getRestartCause(RestartCause::powerButton);
718 }
719 else if (causeSet.contains(RestartCause::powerPolicyOn))
720 {
721 restartCause = getRestartCause(RestartCause::powerPolicyOn);
722 }
723 else if (causeSet.contains(RestartCause::powerPolicyRestore))
724 {
725 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
726 }
727 else if (causeSet.contains(RestartCause::softReset))
728 {
Matt Simmering58e379d2022-09-23 14:45:50 -0700729#if IGNORE_SOFT_RESETS_DURING_POST
730 if (ignoreNextSoftReset)
731 {
732 ignoreNextSoftReset = false;
733 return;
734 }
735#endif
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700736 restartCause = getRestartCause(RestartCause::softReset);
737 }
738
739 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700740}
741
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700742static void systemPowerGoodFailedLog()
743{
744 sd_journal_send(
745 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
746 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
747 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700748 TimerMap["SioPowerGoodWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700749}
750
751static void psPowerOKFailedLog()
752{
753 sd_journal_send(
754 "MESSAGE=PowerControl: power supply power good failed to assert",
755 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
756 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700757 TimerMap["PsPowerOKWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700758}
759
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700760static void powerRestorePolicyLog()
761{
762 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
763 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
764 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
765}
766
767static void powerButtonPressLog()
768{
769 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
770 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
771 "OpenBMC.0.1.PowerButtonPressed", NULL);
772}
773
774static void resetButtonPressLog()
775{
776 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
777 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
778 "OpenBMC.0.1.ResetButtonPressed", NULL);
779}
780
781static void nmiButtonPressLog()
782{
783 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
784 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
785 "OpenBMC.0.1.NMIButtonPressed", NULL);
786}
787
788static void nmiDiagIntLog()
789{
790 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
791 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
792 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
793}
794
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300795PersistentState::PersistentState()
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700796{
797 // create the power control directory if it doesn't exist
798 std::error_code ec;
799 if (!(std::filesystem::create_directories(powerControlDir, ec)))
800 {
801 if (ec.value() != 0)
802 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800803 lg2::error("failed to create {DIR_NAME}: {ERROR_MSG}", "DIR_NAME",
804 powerControlDir.string(), "ERROR_MSG", ec.message());
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300805 throw std::runtime_error("Failed to create state directory");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700806 }
807 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300808
809 // read saved state, it's ok, if the file doesn't exists
810 std::ifstream appStateStream(powerControlDir / stateFile);
811 if (!appStateStream.is_open())
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700812 {
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300813 lg2::info("Cannot open state file \'{PATH}\'", "PATH",
814 std::string(powerControlDir / stateFile));
815 stateData = nlohmann::json({});
816 return;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700817 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300818 try
819 {
820 appStateStream >> stateData;
821 if (stateData.is_discarded())
822 {
823 lg2::info("Cannot parse state file \'{PATH}\'", "PATH",
824 std::string(powerControlDir / stateFile));
825 stateData = nlohmann::json({});
826 return;
827 }
828 }
829 catch (const std::exception& ex)
830 {
831 lg2::info("Cannot read state file \'{PATH}\'", "PATH",
832 std::string(powerControlDir / stateFile));
833 stateData = nlohmann::json({});
834 return;
835 }
836}
837PersistentState::~PersistentState()
838{
839 saveState();
840}
841const std::string PersistentState::get(Params parameter)
842{
843 auto val = stateData.find(getName(parameter));
844 if (val != stateData.end())
845 {
846 return val->get<std::string>();
847 }
848 return getDefault(parameter);
849}
850void PersistentState::set(Params parameter, const std::string& value)
851{
852 stateData[getName(parameter)] = value;
853 saveState();
854}
855
856const std::string PersistentState::getName(const Params parameter)
857{
858 switch (parameter)
859 {
860 case Params::PowerState:
861 return "PowerState";
862 }
863 return "";
864}
865const std::string PersistentState::getDefault(const Params parameter)
866{
867 switch (parameter)
868 {
869 case Params::PowerState:
870 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
871 }
872 return "";
873}
874void PersistentState::saveState()
875{
876 std::ofstream appStateStream(powerControlDir / stateFile, std::ios::trunc);
877 if (!appStateStream.is_open())
878 {
879 lg2::error("Cannot write state file \'{PATH}\'", "PATH",
880 std::string(powerControlDir / stateFile));
881 return;
882 }
883 appStateStream << stateData.dump(indentationSize);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700884}
885
Patrick Williams48aa1f02023-05-10 07:50:30 -0500886static constexpr const char* setingsService = "xyz.openbmc_project.Settings";
887static constexpr const char* powerRestorePolicyIface =
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300888 "xyz.openbmc_project.Control.Power.RestorePolicy";
889#ifdef USE_ACBOOT
Patrick Williams48aa1f02023-05-10 07:50:30 -0500890static constexpr const char* powerACBootObject =
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300891 "/xyz/openbmc_project/control/host0/ac_boot";
Patrick Williams48aa1f02023-05-10 07:50:30 -0500892static constexpr const char* powerACBootIface =
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300893 "xyz.openbmc_project.Common.ACBoot";
894#endif // USE_ACBOOT
895
896namespace match_rules = sdbusplus::bus::match::rules;
897
898static int powerRestoreConfigHandler(sd_bus_message* m, void* context,
899 sd_bus_error*)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700900{
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300901 if (context == nullptr || m == nullptr)
902 {
903 throw std::runtime_error("Invalid match");
904 }
Patrick Williams439b9c32022-07-22 19:26:53 -0500905 sdbusplus::message_t message(m);
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300906 PowerRestoreController* powerRestore =
907 static_cast<PowerRestoreController*>(context);
908
909 if (std::string(message.get_member()) == "InterfacesAdded")
910 {
911 sdbusplus::message::object_path path;
912 boost::container::flat_map<std::string, dbusPropertiesList> data;
913
914 message.read(path, data);
915
916 for (auto& [iface, properties] : data)
917 {
918 if ((iface == powerRestorePolicyIface)
919#ifdef USE_ACBOOT
920 || (iface == powerACBootIface)
921#endif // USE_ACBOOT
922 )
923 {
924 powerRestore->setProperties(properties);
925 }
926 }
927 }
928 else if (std::string(message.get_member()) == "PropertiesChanged")
929 {
930 std::string interfaceName;
931 dbusPropertiesList propertiesChanged;
932
933 message.read(interfaceName, propertiesChanged);
934
935 powerRestore->setProperties(propertiesChanged);
936 }
937 return 1;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700938}
939
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300940void PowerRestoreController::run()
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700941{
Patrick Williams48aa1f02023-05-10 07:50:30 -0500942 std::string powerRestorePolicyObject = "/xyz/openbmc_project/control/host" +
943 node + "/power_restore_policy";
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300944 powerRestorePolicyLog();
945 // this list only needs to be created once
946 if (matches.empty())
947 {
948 matches.emplace_back(
949 *conn,
950 match_rules::interfacesAdded() +
951 match_rules::argNpath(0, powerRestorePolicyObject) +
952 match_rules::sender(setingsService),
953 powerRestoreConfigHandler, this);
954#ifdef USE_ACBOOT
955 matches.emplace_back(*conn,
956 match_rules::interfacesAdded() +
957 match_rules::argNpath(0, powerACBootObject) +
958 match_rules::sender(setingsService),
959 powerRestoreConfigHandler, this);
960 matches.emplace_back(*conn,
961 match_rules::propertiesChanged(powerACBootObject,
962 powerACBootIface) +
963 match_rules::sender(setingsService),
964 powerRestoreConfigHandler, this);
965#endif // USE_ACBOOT
966 }
967
968 // Check if it's already on DBus
969 conn->async_method_call(
970 [this](boost::system::error_code ec,
971 const dbusPropertiesList properties) {
Patrick Williams48aa1f02023-05-10 07:50:30 -0500972 if (ec)
973 {
974 return;
975 }
976 setProperties(properties);
Patrick Williamsd394c882023-10-20 11:18:44 -0500977 },
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300978 setingsService, powerRestorePolicyObject,
979 "org.freedesktop.DBus.Properties", "GetAll", powerRestorePolicyIface);
980
981#ifdef USE_ACBOOT
982 // Check if it's already on DBus
983 conn->async_method_call(
984 [this](boost::system::error_code ec,
985 const dbusPropertiesList properties) {
Patrick Williams48aa1f02023-05-10 07:50:30 -0500986 if (ec)
987 {
988 return;
989 }
990 setProperties(properties);
Patrick Williamsd394c882023-10-20 11:18:44 -0500991 },
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300992 setingsService, powerACBootObject, "org.freedesktop.DBus.Properties",
993 "GetAll", powerACBootIface);
994#endif
995}
996
997void PowerRestoreController::setProperties(const dbusPropertiesList& props)
998{
999 for (auto& [property, propValue] : props)
1000 {
1001 if (property == "PowerRestorePolicy")
1002 {
1003 const std::string* value = std::get_if<std::string>(&propValue);
1004 if (value == nullptr)
1005 {
1006 lg2::error("Unable to read Power Restore Policy");
1007 continue;
1008 }
1009 powerRestorePolicy = *value;
1010 }
1011 else if (property == "PowerRestoreDelay")
1012 {
1013 const uint64_t* value = std::get_if<uint64_t>(&propValue);
1014 if (value == nullptr)
1015 {
1016 lg2::error("Unable to read Power Restore Delay");
1017 continue;
1018 }
1019 powerRestoreDelay = *value / 1000000; // usec to sec
1020 }
1021#ifdef USE_ACBOOT
1022 else if (property == "ACBoot")
1023 {
1024 const std::string* value = std::get_if<std::string>(&propValue);
1025 if (value == nullptr)
1026 {
1027 lg2::error("Unable to read AC Boot status");
1028 continue;
1029 }
1030 acBoot = *value;
1031 }
1032#endif // USE_ACBOOT
1033 }
1034 invokeIfReady();
1035}
1036
1037void PowerRestoreController::invokeIfReady()
1038{
1039 if ((powerRestorePolicy.empty()) || (powerRestoreDelay < 0))
1040 {
1041 return;
1042 }
1043#ifdef USE_ACBOOT
1044 if (acBoot.empty() || acBoot == "Unknown")
1045 {
1046 return;
1047 }
1048#endif
1049
1050 matches.clear();
1051 if (!timerFired)
1052 {
1053 // Calculate the delay from now to meet the requested delay
1054 // Subtract the approximate uboot time
1055 static constexpr const int ubootSeconds = 20;
1056 int delay = powerRestoreDelay - ubootSeconds;
1057 // Subtract the time since boot
1058 struct sysinfo info = {};
1059 if (sysinfo(&info) == 0)
1060 {
1061 delay -= info.uptime;
1062 }
1063
1064 if (delay > 0)
1065 {
1066 powerRestoreTimer.expires_after(std::chrono::seconds(delay));
1067 lg2::info("Power Restore delay of {DELAY} seconds started", "DELAY",
1068 delay);
Patrick Williams48aa1f02023-05-10 07:50:30 -05001069 powerRestoreTimer.async_wait(
1070 [this](const boost::system::error_code ec) {
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001071 if (ec)
1072 {
1073 // operation_aborted is expected if timer is canceled before
1074 // completion.
1075 if (ec == boost::asio::error::operation_aborted)
1076 {
1077 return;
1078 }
1079 lg2::error(
1080 "power restore policy async_wait failed: {ERROR_MSG}",
1081 "ERROR_MSG", ec.message());
1082 }
1083 else
1084 {
1085 lg2::info("Power Restore delay timer expired");
1086 }
1087 invoke();
1088 });
1089 timerFired = true;
1090 }
1091 else
1092 {
1093 invoke();
1094 }
1095 }
1096}
1097
1098void PowerRestoreController::invoke()
1099{
1100 // we want to run Power Restore only once
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001101 if (policyInvoked)
1102 {
1103 return;
1104 }
1105 policyInvoked = true;
1106
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001107 lg2::info("Invoking Power Restore Policy {POLICY}", "POLICY",
1108 powerRestorePolicy);
1109 if (powerRestorePolicy ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001110 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
1111 {
1112 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001113 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001114 }
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001115 else if (powerRestorePolicy ==
Jason M. Bills418ce112021-09-08 15:15:05 -07001116 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore")
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001117 {
1118 if (wasPowerDropped())
1119 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001120 lg2::info("Power was dropped, restoring Host On state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001121 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001122 setRestartCauseProperty(
1123 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001124 }
1125 else
1126 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001127 lg2::info("No power drop, restoring Host Off state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001128 }
1129 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -07001130 // We're done with the previous power state for the restore policy, so store
1131 // the current state
1132 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001133}
1134
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001135bool PowerRestoreController::wasPowerDropped()
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001136{
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001137 std::string state = appState.get(PersistentState::Params::PowerState);
1138 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001139}
1140
Zev Weiss676ef2c2021-09-02 21:54:02 -05001141static void waitForGPIOEvent(const std::string& name,
1142 const std::function<void(bool)>& eventHandler,
1143 gpiod::line& line,
1144 boost::asio::posix::stream_descriptor& event)
1145{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001146 event.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1147 [&name, eventHandler, &line,
1148 &event](const boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001149 if (ec)
1150 {
1151 lg2::error("{GPIO_NAME} fd handler error: {ERROR_MSG}", "GPIO_NAME",
1152 name, "ERROR_MSG", ec.message());
1153 // TODO: throw here to force power-control to
1154 // restart?
1155 return;
1156 }
1157 gpiod::line_event line_event = line.event_read();
1158 eventHandler(line_event.event_type == gpiod::line_event::RISING_EDGE);
1159 waitForGPIOEvent(name, eventHandler, line, event);
1160 });
Zev Weiss676ef2c2021-09-02 21:54:02 -05001161}
1162
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001163static bool requestGPIOEvents(
Zev Weiss676ef2c2021-09-02 21:54:02 -05001164 const std::string& name, const std::function<void(bool)>& handler,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001165 gpiod::line& gpioLine,
1166 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
1167{
1168 // Find the GPIO line
1169 gpioLine = gpiod::find_line(name);
1170 if (!gpioLine)
1171 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001172 lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001173 return false;
1174 }
1175
1176 try
1177 {
Andrei Kartashev3efcf372021-12-29 15:32:17 +03001178 gpioLine.request({appName, gpiod::line_request::EVENT_BOTH_EDGES, {}});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001179 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001180 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001181 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001182 lg2::error("Failed to request events for {GPIO_NAME}: {ERROR}",
1183 "GPIO_NAME", name, "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001184 return false;
1185 }
1186
1187 int gpioLineFd = gpioLine.event_get_fd();
1188 if (gpioLineFd < 0)
1189 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001190 lg2::error("Failed to get {GPIO_NAME} fd", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001191 return false;
1192 }
1193
1194 gpioEventDescriptor.assign(gpioLineFd);
1195
Zev Weiss676ef2c2021-09-02 21:54:02 -05001196 waitForGPIOEvent(name, handler, gpioLine, gpioEventDescriptor);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001197 return true;
1198}
1199
1200static bool setGPIOOutput(const std::string& name, const int value,
1201 gpiod::line& gpioLine)
1202{
1203 // Find the GPIO line
1204 gpioLine = gpiod::find_line(name);
1205 if (!gpioLine)
1206 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001207 lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001208 return false;
1209 }
1210
1211 // Request GPIO output to specified value
1212 try
1213 {
Andrei Kartashev3efcf372021-12-29 15:32:17 +03001214 gpioLine.request({appName, gpiod::line_request::DIRECTION_OUTPUT, {}},
1215 value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001216 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001217 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001218 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001219 lg2::error("Failed to request {GPIO_NAME} output: {ERROR}", "GPIO_NAME",
1220 name, "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001221 return false;
1222 }
1223
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001224 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1225 "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001226 return true;
1227}
1228
1229static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1230 const std::string& name, const int value,
1231 const int durationMs)
1232{
1233 // Set the masked GPIO line to the specified value
1234 maskedGPIOLine.set_value(value);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001235 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1236 "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001237 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001238 gpioAssertTimer.async_wait(
1239 [maskedGPIOLine, value, name](const boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001240 // Set the masked GPIO line back to the opposite value
1241 maskedGPIOLine.set_value(!value);
1242 lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
1243 if (ec)
1244 {
1245 // operation_aborted is expected if timer is canceled before
1246 // completion.
1247 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001248 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001249 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1250 "GPIO_NAME", name, "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001251 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05001252 }
1253 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001254 return 0;
1255}
1256
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001257static int setGPIOOutputForMs(const ConfigData& config, const int value,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001258 const int durationMs)
1259{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001260 // If the requested GPIO is masked, use the mask line to set the output
1261 if (powerButtonMask && config.lineName == powerOutConfig.lineName)
1262 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001263 return setMaskedGPIOOutputForMs(powerButtonMask, config.lineName, value,
1264 durationMs);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001265 }
1266 if (resetButtonMask && config.lineName == resetOutConfig.lineName)
1267 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001268 return setMaskedGPIOOutputForMs(resetButtonMask, config.lineName, value,
1269 durationMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001270 }
1271
1272 // No mask set, so request and set the GPIO normally
1273 gpiod::line gpioLine;
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001274 if (!setGPIOOutput(config.lineName, value, gpioLine))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001275 {
1276 return -1;
1277 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001278 const std::string name = config.lineName;
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001279
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001280 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001281 gpioAssertTimer.async_wait(
1282 [gpioLine, value, name](const boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001283 // Set the GPIO line back to the opposite value
1284 gpioLine.set_value(!value);
1285 lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
1286 if (ec)
1287 {
1288 // operation_aborted is expected if timer is canceled before
1289 // completion.
1290 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001291 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001292 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1293 "GPIO_NAME", name, "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001294 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05001295 }
1296 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001297 return 0;
1298}
1299
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001300static int assertGPIOForMs(const ConfigData& config, const int durationMs)
1301{
1302 return setGPIOOutputForMs(config, config.polarity, durationMs);
1303}
1304
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001305static void powerOn()
1306{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001307 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001308}
Naveen Moses117c34e2021-05-26 20:10:51 +05301309#ifdef CHASSIS_SYSTEM_RESET
1310static int slotPowerOn()
1311{
1312 if (power_control::slotPowerState != power_control::SlotPowerState::on)
1313 {
Naveen Moses117c34e2021-05-26 20:10:51 +05301314 slotPowerLine.set_value(1);
1315
1316 if (slotPowerLine.get_value() > 0)
1317 {
1318 setSlotPowerState(SlotPowerState::on);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001319 lg2::info("Slot Power is switched On\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301320 }
1321 else
1322 {
1323 return -1;
1324 }
1325 }
1326 else
1327 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001328 lg2::info("Slot Power is already in 'On' state\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301329 return -1;
1330 }
1331 return 0;
1332}
1333static int slotPowerOff()
1334{
1335 if (power_control::slotPowerState != power_control::SlotPowerState::off)
1336 {
1337 slotPowerLine.set_value(0);
1338
1339 if (!(slotPowerLine.get_value() > 0))
1340 {
1341 setSlotPowerState(SlotPowerState::off);
1342 setPowerState(PowerState::off);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001343 lg2::info("Slot Power is switched Off\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301344 }
1345 else
1346 {
1347 return -1;
1348 }
1349 }
1350 else
1351 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001352 lg2::info("Slot Power is already in 'Off' state\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301353 return -1;
1354 }
1355 return 0;
1356}
1357static void slotPowerCycle()
1358{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001359 lg2::info("Slot Power Cycle started\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301360 slotPowerOff();
1361 slotPowerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001362 std::chrono::milliseconds(TimerMap["SlotPowerCycleMs"]));
Naveen Moses117c34e2021-05-26 20:10:51 +05301363 slotPowerCycleTimer.async_wait([](const boost::system::error_code ec) {
1364 if (ec)
1365 {
1366 if (ec != boost::asio::error::operation_aborted)
1367 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001368 lg2::error(
1369 "Slot Power cycle timer async_wait failed: {ERROR_MSG}",
1370 "ERROR_MSG", ec.message());
Naveen Moses117c34e2021-05-26 20:10:51 +05301371 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001372 lg2::info("Slot Power cycle timer canceled\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301373 return;
1374 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001375 lg2::info("Slot Power cycle timer completed\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301376 slotPowerOn();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001377 lg2::info("Slot Power Cycle Completed\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301378 });
1379}
1380#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001381static void gracefulPowerOff()
1382{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001383 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001384}
1385
1386static void forcePowerOff()
1387{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001388 if (assertGPIOForMs(powerOutConfig, TimerMap["ForceOffPulseMs"]) < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001389 {
1390 return;
1391 }
1392
Jason M. Billsc6961b62021-10-21 14:08:02 -07001393 // If the force off timer expires, then the power-button override failed
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001394 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1395 if (ec)
1396 {
1397 // operation_aborted is expected if timer is canceled before
1398 // completion.
1399 if (ec != boost::asio::error::operation_aborted)
1400 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001401 lg2::error("Force power off async_wait failed: {ERROR_MSG}",
1402 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001403 }
1404 return;
1405 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001406
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001407 lg2::error("Power-button override failed. Not sure what to do now.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001408 });
1409}
1410
1411static void reset()
1412{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001413 assertGPIOForMs(resetOutConfig, TimerMap["ResetPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001414}
1415
1416static void gracefulPowerOffTimerStart()
1417{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001418 lg2::info("Graceful power-off timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001419 gracefulPowerOffTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001420 std::chrono::seconds(TimerMap["GracefulPowerOffS"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001421 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1422 if (ec)
1423 {
1424 // operation_aborted is expected if timer is canceled before
1425 // completion.
1426 if (ec != boost::asio::error::operation_aborted)
1427 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001428 lg2::error("Graceful power-off async_wait failed: {ERROR_MSG}",
1429 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001430 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001431 lg2::info("Graceful power-off timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001432 return;
1433 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001434 lg2::info("Graceful power-off timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001435 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1436 });
1437}
1438
1439static void powerCycleTimerStart()
1440{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001441 lg2::info("Power-cycle timer started");
Priyatharshan P70120512020-09-16 18:47:20 +05301442 powerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001443 std::chrono::milliseconds(TimerMap["PowerCycleMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001444 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1445 if (ec)
1446 {
1447 // operation_aborted is expected if timer is canceled before
1448 // completion.
1449 if (ec != boost::asio::error::operation_aborted)
1450 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001451 lg2::error("Power-cycle async_wait failed: {ERROR_MSG}",
1452 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001453 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001454 lg2::info("Power-cycle timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001455 return;
1456 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001457 lg2::info("Power-cycle timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001458 sendPowerControlEvent(Event::powerCycleTimerExpired);
1459 });
1460}
1461
1462static void psPowerOKWatchdogTimerStart()
1463{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001464 lg2::info("power supply power OK watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001465 psPowerOKWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001466 std::chrono::milliseconds(TimerMap["PsPowerOKWatchdogMs"]));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001467 psPowerOKWatchdogTimer.async_wait([](const boost::system::error_code ec) {
1468 if (ec)
1469 {
1470 // operation_aborted is expected if timer is canceled before
1471 // completion.
1472 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001473 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001474 lg2::error(
1475 "power supply power OK watchdog async_wait failed: {ERROR_MSG}",
1476 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001477 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001478 lg2::info("power supply power OK watchdog timer canceled");
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001479 return;
1480 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001481 lg2::info("power supply power OK watchdog timer expired");
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001482 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1483 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001484}
1485
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001486static void warmResetCheckTimerStart()
1487{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001488 lg2::info("Warm reset check timer started");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001489 warmResetCheckTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001490 std::chrono::milliseconds(TimerMap["WarmResetCheckMs"]));
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001491 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1492 if (ec)
1493 {
1494 // operation_aborted is expected if timer is canceled before
1495 // completion.
1496 if (ec != boost::asio::error::operation_aborted)
1497 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001498 lg2::error("Warm reset check async_wait failed: {ERROR_MSG}",
1499 "ERROR_MSG", ec.message());
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001500 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001501 lg2::info("Warm reset check timer canceled");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001502 return;
1503 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001504 lg2::info("Warm reset check timer completed");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001505 sendPowerControlEvent(Event::warmResetDetected);
1506 });
1507}
1508
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001509static void pohCounterTimerStart()
1510{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001511 lg2::info("POH timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001512 // Set the time-out as 1 hour, to align with POH command in ipmid
1513 pohCounterTimer.expires_after(std::chrono::hours(1));
1514 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1515 if (ec)
1516 {
1517 // operation_aborted is expected if timer is canceled before
1518 // completion.
1519 if (ec != boost::asio::error::operation_aborted)
1520 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001521 lg2::error("POH timer async_wait failed: {ERROR_MSG}",
1522 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001523 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001524 lg2::info("POH timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001525 return;
1526 }
1527
1528 if (getHostState(powerState) !=
1529 "xyz.openbmc_project.State.Host.HostState.Running")
1530 {
1531 return;
1532 }
1533
1534 conn->async_method_call(
1535 [](boost::system::error_code ec,
1536 const std::variant<uint32_t>& pohCounterProperty) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001537 if (ec)
1538 {
1539 lg2::error("error getting poh counter");
1540 return;
1541 }
1542 const uint32_t* pohCounter =
1543 std::get_if<uint32_t>(&pohCounterProperty);
1544 if (pohCounter == nullptr)
1545 {
1546 lg2::error("unable to read poh counter");
1547 return;
1548 }
1549
1550 conn->async_method_call(
1551 [](boost::system::error_code ec) {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001552 if (ec)
1553 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001554 lg2::error("failed to set poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001555 }
Patrick Williamsd394c882023-10-20 11:18:44 -05001556 },
Patrick Williams48aa1f02023-05-10 07:50:30 -05001557 "xyz.openbmc_project.Settings",
1558 "/xyz/openbmc_project/state/chassis0",
1559 "org.freedesktop.DBus.Properties", "Set",
1560 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1561 std::variant<uint32_t>(*pohCounter + 1));
Patrick Williamsd394c882023-10-20 11:18:44 -05001562 },
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001563 "xyz.openbmc_project.Settings",
1564 "/xyz/openbmc_project/state/chassis0",
1565 "org.freedesktop.DBus.Properties", "Get",
1566 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1567
1568 pohCounterTimerStart();
1569 });
1570}
1571
1572static void currentHostStateMonitor()
1573{
Yong Li8d660212019-12-27 10:18:10 +08001574 if (getHostState(powerState) ==
1575 "xyz.openbmc_project.State.Host.HostState.Running")
1576 {
1577 pohCounterTimerStart();
1578 // Clear the restart cause set for the next restart
1579 clearRestartCause();
1580 }
1581 else
1582 {
1583 pohCounterTimer.cancel();
1584 // Set the restart cause set for this restart
1585 setRestartCause();
1586 }
1587
Patrick Williams48aa1f02023-05-10 07:50:30 -05001588 static auto match =
1589 sdbusplus::bus::match_t(*conn,
1590 "type='signal',member='PropertiesChanged', "
1591 "interface='org.freedesktop.DBus.Properties', "
1592 "arg0='xyz.openbmc_project.State.Host'",
1593 [](sdbusplus::message_t& message) {
1594 std::string intfName;
1595 std::map<std::string, std::variant<std::string>> properties;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001596
Patrick Williams48aa1f02023-05-10 07:50:30 -05001597 try
1598 {
1599 message.read(intfName, properties);
1600 }
1601 catch (const std::exception& e)
1602 {
1603 lg2::error("Unable to read host state: {ERROR}", "ERROR", e);
1604 return;
1605 }
1606 if (properties.empty())
1607 {
1608 lg2::error("ERROR: Empty PropertiesChanged signal received");
1609 return;
1610 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001611
Patrick Williams48aa1f02023-05-10 07:50:30 -05001612 // We only want to check for CurrentHostState
1613 if (properties.begin()->first != "CurrentHostState")
1614 {
1615 return;
1616 }
1617 std::string* currentHostState =
1618 std::get_if<std::string>(&(properties.begin()->second));
1619 if (currentHostState == nullptr)
1620 {
1621 lg2::error("{PROPERTY} property invalid", "PROPERTY",
1622 properties.begin()->first);
1623 return;
1624 }
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001625
Patrick Williams48aa1f02023-05-10 07:50:30 -05001626 if (*currentHostState ==
1627 "xyz.openbmc_project.State.Host.HostState.Running")
1628 {
1629 pohCounterTimerStart();
1630 // Clear the restart cause set for the next restart
1631 clearRestartCause();
1632 sd_journal_send("MESSAGE=Host system DC power is on", "PRIORITY=%i",
1633 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
1634 "OpenBMC.0.1.DCPowerOn", NULL);
1635 }
1636 else
1637 {
1638 pohCounterTimer.cancel();
1639 // POST_COMPLETE GPIO event is not working in some platforms
1640 // when power state is changed to OFF. This resulted in
1641 // 'OperatingSystemState' to stay at 'Standby', even though
1642 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1643 // if HostState is trurned to OFF.
1644 setOperatingSystemState(OperatingSystemStateStage::Inactive);
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301645
Patrick Williams48aa1f02023-05-10 07:50:30 -05001646 // Set the restart cause set for this restart
1647 setRestartCause();
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001648#ifdef USE_ACBOOT
Patrick Williams48aa1f02023-05-10 07:50:30 -05001649 resetACBootProperty();
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001650#endif // USE_ACBOOT
Patrick Williams48aa1f02023-05-10 07:50:30 -05001651 sd_journal_send("MESSAGE=Host system DC power is off",
1652 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
1653 "OpenBMC.0.1.DCPowerOff", NULL);
1654 }
Patrick Williamsd394c882023-10-20 11:18:44 -05001655 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001656}
1657
1658static void sioPowerGoodWatchdogTimerStart()
1659{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001660 lg2::info("SIO power good watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001661 sioPowerGoodWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001662 std::chrono::milliseconds(TimerMap["SioPowerGoodWatchdogMs"]));
Patrick Williams48aa1f02023-05-10 07:50:30 -05001663 sioPowerGoodWatchdogTimer.async_wait(
1664 [](const boost::system::error_code ec) {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001665 if (ec)
1666 {
1667 // operation_aborted is expected if timer is canceled before
1668 // completion.
1669 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001670 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001671 lg2::error(
1672 "SIO power good watchdog async_wait failed: {ERROR_MSG}",
1673 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001674 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001675 lg2::info("SIO power good watchdog timer canceled");
1676 return;
1677 }
1678 lg2::info("SIO power good watchdog timer completed");
1679 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1680 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001681}
1682
1683static void powerStateOn(const Event event)
1684{
1685 logEvent(__FUNCTION__, event);
1686 switch (event)
1687 {
1688 case Event::psPowerOKDeAssert:
1689 setPowerState(PowerState::off);
1690 // DC power is unexpectedly lost, beep
1691 beep(beepPowerFail);
1692 break;
1693 case Event::sioS5Assert:
1694 setPowerState(PowerState::transitionToOff);
Matt Simmering58e379d2022-09-23 14:45:50 -07001695#if IGNORE_SOFT_RESETS_DURING_POST
1696 // Only recognize soft resets once host gets past POST COMPLETE
1697 if (operatingSystemState != OperatingSystemStateStage::Standby)
1698 {
1699 ignoreNextSoftReset = true;
1700 }
1701#endif
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001702 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001703 break;
Jason M. Billsfb957332021-01-28 13:18:46 -08001704#if USE_PLT_RST
1705 case Event::pltRstAssert:
1706#else
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001707 case Event::postCompleteDeAssert:
Jason M. Billsfb957332021-01-28 13:18:46 -08001708#endif
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001709 setPowerState(PowerState::checkForWarmReset);
Matt Simmering58e379d2022-09-23 14:45:50 -07001710#if IGNORE_SOFT_RESETS_DURING_POST
1711 // Only recognize soft resets once host gets past POST COMPLETE
1712 if (operatingSystemState != OperatingSystemStateStage::Standby)
1713 {
1714 ignoreNextSoftReset = true;
1715 }
1716#endif
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001717 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001718 warmResetCheckTimerStart();
1719 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001720 case Event::powerButtonPressed:
1721 setPowerState(PowerState::gracefulTransitionToOff);
1722 gracefulPowerOffTimerStart();
1723 break;
1724 case Event::powerOffRequest:
1725 setPowerState(PowerState::transitionToOff);
1726 forcePowerOff();
1727 break;
1728 case Event::gracefulPowerOffRequest:
1729 setPowerState(PowerState::gracefulTransitionToOff);
1730 gracefulPowerOffTimerStart();
1731 gracefulPowerOff();
1732 break;
1733 case Event::powerCycleRequest:
1734 setPowerState(PowerState::transitionToCycleOff);
1735 forcePowerOff();
1736 break;
1737 case Event::gracefulPowerCycleRequest:
1738 setPowerState(PowerState::gracefulTransitionToCycleOff);
1739 gracefulPowerOffTimerStart();
1740 gracefulPowerOff();
1741 break;
1742 case Event::resetRequest:
1743 reset();
1744 break;
1745 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001746 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001747 break;
1748 }
1749}
1750
1751static void powerStateWaitForPSPowerOK(const Event event)
1752{
1753 logEvent(__FUNCTION__, event);
1754 switch (event)
1755 {
1756 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301757 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001758 // Cancel any GPIO assertions held during the transition
1759 gpioAssertTimer.cancel();
1760 psPowerOKWatchdogTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301761 if (sioEnabled == true)
1762 {
1763 sioPowerGoodWatchdogTimerStart();
1764 setPowerState(PowerState::waitForSIOPowerGood);
1765 }
1766 else
1767 {
1768 setPowerState(PowerState::on);
1769 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001770 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301771 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001772 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001773 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001774 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001775 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001776 case Event::sioPowerGoodAssert:
1777 psPowerOKWatchdogTimer.cancel();
1778 setPowerState(PowerState::on);
1779 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001780 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001781 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001782 break;
1783 }
1784}
1785
1786static void powerStateWaitForSIOPowerGood(const Event event)
1787{
1788 logEvent(__FUNCTION__, event);
1789 switch (event)
1790 {
1791 case Event::sioPowerGoodAssert:
1792 sioPowerGoodWatchdogTimer.cancel();
1793 setPowerState(PowerState::on);
1794 break;
1795 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001796 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001797 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001798 break;
1799 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001800 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001801 break;
1802 }
1803}
1804
1805static void powerStateOff(const Event event)
1806{
1807 logEvent(__FUNCTION__, event);
1808 switch (event)
1809 {
1810 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301811 {
1812 if (sioEnabled == true)
1813 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001814 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301815 setPowerState(PowerState::waitForSIOPowerGood);
1816 }
1817 else
1818 {
1819 setPowerState(PowerState::on);
1820 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001821 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301822 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001823 case Event::sioS5DeAssert:
Jason M. Billsfe159032022-09-01 16:03:37 -07001824 psPowerOKWatchdogTimerStart();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001825 setPowerState(PowerState::waitForPSPowerOK);
1826 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001827 case Event::sioPowerGoodAssert:
1828 setPowerState(PowerState::on);
1829 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001830 case Event::powerButtonPressed:
1831 psPowerOKWatchdogTimerStart();
1832 setPowerState(PowerState::waitForPSPowerOK);
1833 break;
1834 case Event::powerOnRequest:
1835 psPowerOKWatchdogTimerStart();
1836 setPowerState(PowerState::waitForPSPowerOK);
1837 powerOn();
1838 break;
1839 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001840 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001841 break;
1842 }
1843}
1844
1845static void powerStateTransitionToOff(const Event event)
1846{
1847 logEvent(__FUNCTION__, event);
1848 switch (event)
1849 {
1850 case Event::psPowerOKDeAssert:
1851 // Cancel any GPIO assertions held during the transition
1852 gpioAssertTimer.cancel();
1853 setPowerState(PowerState::off);
1854 break;
1855 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001856 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001857 break;
1858 }
1859}
1860
1861static void powerStateGracefulTransitionToOff(const Event event)
1862{
1863 logEvent(__FUNCTION__, event);
1864 switch (event)
1865 {
1866 case Event::psPowerOKDeAssert:
1867 gracefulPowerOffTimer.cancel();
1868 setPowerState(PowerState::off);
1869 break;
1870 case Event::gracefulPowerOffTimerExpired:
1871 setPowerState(PowerState::on);
1872 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001873 case Event::powerOffRequest:
1874 gracefulPowerOffTimer.cancel();
1875 setPowerState(PowerState::transitionToOff);
1876 forcePowerOff();
1877 break;
1878 case Event::powerCycleRequest:
1879 gracefulPowerOffTimer.cancel();
1880 setPowerState(PowerState::transitionToCycleOff);
1881 forcePowerOff();
1882 break;
1883 case Event::resetRequest:
1884 gracefulPowerOffTimer.cancel();
1885 setPowerState(PowerState::on);
1886 reset();
1887 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001888 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001889 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001890 break;
1891 }
1892}
1893
1894static void powerStateCycleOff(const Event event)
1895{
1896 logEvent(__FUNCTION__, event);
1897 switch (event)
1898 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001899 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301900 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001901 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301902 if (sioEnabled == true)
1903 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001904 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301905 setPowerState(PowerState::waitForSIOPowerGood);
1906 }
1907 else
1908 {
1909 setPowerState(PowerState::on);
1910 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001911 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301912 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001913 case Event::sioS5DeAssert:
1914 powerCycleTimer.cancel();
Jason M. Billsfe159032022-09-01 16:03:37 -07001915 psPowerOKWatchdogTimerStart();
Jason M. Bills35aa6652020-04-30 16:24:55 -07001916 setPowerState(PowerState::waitForPSPowerOK);
1917 break;
1918 case Event::powerButtonPressed:
1919 powerCycleTimer.cancel();
1920 psPowerOKWatchdogTimerStart();
1921 setPowerState(PowerState::waitForPSPowerOK);
1922 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001923 case Event::powerCycleTimerExpired:
1924 psPowerOKWatchdogTimerStart();
1925 setPowerState(PowerState::waitForPSPowerOK);
1926 powerOn();
1927 break;
1928 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001929 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001930 break;
1931 }
1932}
1933
1934static void powerStateTransitionToCycleOff(const Event event)
1935{
1936 logEvent(__FUNCTION__, event);
1937 switch (event)
1938 {
1939 case Event::psPowerOKDeAssert:
1940 // Cancel any GPIO assertions held during the transition
1941 gpioAssertTimer.cancel();
1942 setPowerState(PowerState::cycleOff);
1943 powerCycleTimerStart();
1944 break;
1945 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001946 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001947 break;
1948 }
1949}
1950
1951static void powerStateGracefulTransitionToCycleOff(const Event event)
1952{
1953 logEvent(__FUNCTION__, event);
1954 switch (event)
1955 {
1956 case Event::psPowerOKDeAssert:
1957 gracefulPowerOffTimer.cancel();
1958 setPowerState(PowerState::cycleOff);
1959 powerCycleTimerStart();
1960 break;
1961 case Event::gracefulPowerOffTimerExpired:
1962 setPowerState(PowerState::on);
1963 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001964 case Event::powerOffRequest:
1965 gracefulPowerOffTimer.cancel();
1966 setPowerState(PowerState::transitionToOff);
1967 forcePowerOff();
1968 break;
1969 case Event::powerCycleRequest:
1970 gracefulPowerOffTimer.cancel();
1971 setPowerState(PowerState::transitionToCycleOff);
1972 forcePowerOff();
1973 break;
1974 case Event::resetRequest:
1975 gracefulPowerOffTimer.cancel();
1976 setPowerState(PowerState::on);
1977 reset();
1978 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001979 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001980 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001981 break;
1982 }
1983}
1984
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001985static void powerStateCheckForWarmReset(const Event event)
1986{
1987 logEvent(__FUNCTION__, event);
1988 switch (event)
1989 {
1990 case Event::sioS5Assert:
1991 warmResetCheckTimer.cancel();
1992 setPowerState(PowerState::transitionToOff);
1993 break;
1994 case Event::warmResetDetected:
1995 setPowerState(PowerState::on);
1996 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001997 case Event::psPowerOKDeAssert:
1998 warmResetCheckTimer.cancel();
1999 setPowerState(PowerState::off);
2000 // DC power is unexpectedly lost, beep
2001 beep(beepPowerFail);
2002 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002003 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002004 lg2::info("No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002005 break;
2006 }
2007}
2008
Zev Weiss584aa132021-09-02 19:21:52 -05002009static void psPowerOKHandler(bool state)
2010{
Patrick Williams48aa1f02023-05-10 07:50:30 -05002011 Event powerControlEvent = state ? Event::psPowerOKAssert
2012 : Event::psPowerOKDeAssert;
Zev Weiss584aa132021-09-02 19:21:52 -05002013 sendPowerControlEvent(powerControlEvent);
2014}
2015
Zev Weiss584aa132021-09-02 19:21:52 -05002016static void sioPowerGoodHandler(bool state)
2017{
Patrick Williams48aa1f02023-05-10 07:50:30 -05002018 Event powerControlEvent = state ? Event::sioPowerGoodAssert
2019 : Event::sioPowerGoodDeAssert;
Zev Weiss584aa132021-09-02 19:21:52 -05002020 sendPowerControlEvent(powerControlEvent);
2021}
2022
Zev Weiss584aa132021-09-02 19:21:52 -05002023static void sioOnControlHandler(bool state)
2024{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002025 lg2::info("SIO_ONCONTROL value changed: {VALUE}", "VALUE",
2026 static_cast<int>(state));
Zev Weiss584aa132021-09-02 19:21:52 -05002027}
2028
Zev Weiss584aa132021-09-02 19:21:52 -05002029static void sioS5Handler(bool state)
2030{
2031 Event powerControlEvent = state ? Event::sioS5DeAssert : Event::sioS5Assert;
2032 sendPowerControlEvent(powerControlEvent);
2033}
2034
Zev Weiss584aa132021-09-02 19:21:52 -05002035static void powerButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002036{
Zev Weiss584aa132021-09-02 19:21:52 -05002037 powerButtonIface->set_property("ButtonPressed", !state);
2038 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002039 {
2040 powerButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002041 if (!powerButtonMask)
2042 {
2043 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002044 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002045 }
2046 else
2047 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002048 lg2::info("power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002049 }
2050 }
Zev Weiss584aa132021-09-02 19:21:52 -05002051}
2052
Zev Weiss584aa132021-09-02 19:21:52 -05002053static void resetButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002054{
Zev Weiss584aa132021-09-02 19:21:52 -05002055 resetButtonIface->set_property("ButtonPressed", !state);
2056 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002057 {
2058 resetButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002059 if (!resetButtonMask)
2060 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002061 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002062 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002063 }
2064 else
2065 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002066 lg2::info("reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002067 }
2068 }
Zev Weiss584aa132021-09-02 19:21:52 -05002069}
2070
Vijay Khemka04175c22020-10-09 14:28:11 -07002071#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002072static constexpr auto systemdBusname = "org.freedesktop.systemd1";
2073static constexpr auto systemdPath = "/org/freedesktop/systemd1";
2074static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
2075static constexpr auto systemTargetName = "chassis-system-reset.target";
2076
2077void systemReset()
2078{
2079 conn->async_method_call(
2080 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002081 if (ec)
2082 {
2083 lg2::error("Failed to call chassis system reset: {ERR}", "ERR",
2084 ec.message());
2085 }
Patrick Williamsd394c882023-10-20 11:18:44 -05002086 },
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002087 systemdBusname, systemdPath, systemdInterface, "StartUnit",
2088 systemTargetName, "replace");
2089}
Vijay Khemka04175c22020-10-09 14:28:11 -07002090#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002091
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002092static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002093{
2094 conn->async_method_call(
2095 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002096 if (ec)
2097 {
2098 lg2::error("failed to set NMI source");
2099 }
Patrick Williamsd394c882023-10-20 11:18:44 -05002100 },
Chen Yugang303bd582019-11-01 08:45:06 +08002101 "xyz.openbmc_project.Settings",
2102 "/xyz/openbmc_project/Chassis/Control/NMISource",
2103 "org.freedesktop.DBus.Properties", "Set",
2104 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
2105 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002106}
2107
2108static void nmiReset(void)
2109{
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002110 const static constexpr int nmiOutPulseTimeMs = 200;
2111
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002112 lg2::info("NMI out action");
Jian Zhang461a1662022-09-22 11:29:01 +08002113 nmiOutLine.set_value(nmiOutConfig.polarity);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002114 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME",
Jian Zhang461a1662022-09-22 11:29:01 +08002115 nmiOutConfig.lineName, "GPIO_VALUE", nmiOutConfig.polarity);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002116 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2117 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2118 // restore the NMI_OUT GPIO line back to the opposite value
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} released", "GPIO_NAME", nmiOutConfig.lineName);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002121 if (ec)
2122 {
2123 // operation_aborted is expected if timer is canceled before
2124 // completion.
2125 if (ec != boost::asio::error::operation_aborted)
2126 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002127 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
2128 "GPIO_NAME", nmiOutConfig.lineName, "ERROR_MSG",
2129 ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002130 }
2131 }
2132 });
2133 // log to redfish
2134 nmiDiagIntLog();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002135 lg2::info("NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002136 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002137 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002138}
2139
2140static void nmiSourcePropertyMonitor(void)
2141{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002142 lg2::info("NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002143
Patrick Williams439b9c32022-07-22 19:26:53 -05002144 static std::unique_ptr<sdbusplus::bus::match_t> nmiSourceMatch =
2145 std::make_unique<sdbusplus::bus::match_t>(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002146 *conn,
2147 "type='signal',interface='org.freedesktop.DBus.Properties',"
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002148 "member='PropertiesChanged',"
2149 "arg0namespace='xyz.openbmc_project.Chassis.Control.NMISource'",
Patrick Williams439b9c32022-07-22 19:26:53 -05002150 [](sdbusplus::message_t& msg) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002151 std::string interfaceName;
2152 boost::container::flat_map<std::string, std::variant<bool, std::string>>
2153 propertiesChanged;
2154 std::string state;
2155 bool value = true;
2156 try
2157 {
2158 msg.read(interfaceName, propertiesChanged);
2159 if (propertiesChanged.begin()->first == "Enabled")
2160 {
2161 value = std::get<bool>(propertiesChanged.begin()->second);
2162 lg2::info("NMI Enabled propertiesChanged value: {VALUE}",
2163 "VALUE", value);
2164 nmiEnabled = value;
2165 if (nmiEnabled)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002166 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002167 nmiReset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002168 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05002169 }
2170 }
2171 catch (const std::exception& e)
2172 {
2173 lg2::error("Unable to read NMI source: {ERROR}", "ERROR", e);
2174 return;
2175 }
Patrick Williamsd394c882023-10-20 11:18:44 -05002176 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002177}
2178
2179static void setNmiSource()
2180{
2181 conn->async_method_call(
2182 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002183 if (ec)
2184 {
2185 lg2::error("failed to set NMI source");
2186 }
Patrick Williamsd394c882023-10-20 11:18:44 -05002187 },
Chen Yugang303bd582019-11-01 08:45:06 +08002188 "xyz.openbmc_project.Settings",
2189 "/xyz/openbmc_project/Chassis/Control/NMISource",
2190 "org.freedesktop.DBus.Properties", "Set",
2191 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
Jason M. Bills418ce112021-09-08 15:15:05 -07002192 std::variant<std::string>{
2193 "xyz.openbmc_project.Chassis.Control.NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002194 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002195 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002196}
2197
Zev Weiss584aa132021-09-02 19:21:52 -05002198static void nmiButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002199{
Olivier FAURAXd7ea2832023-04-14 14:08:02 +00002200 // Don't handle event if host not running and config doesn't force it
2201 if (!nmiWhenPoweredOff &&
2202 getHostState(powerState) !=
2203 "xyz.openbmc_project.State.Host.HostState.Running")
2204 {
2205 return;
2206 }
Zev Weiss584aa132021-09-02 19:21:52 -05002207 nmiButtonIface->set_property("ButtonPressed", !state);
2208 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002209 {
2210 nmiButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002211 if (nmiButtonMasked)
2212 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002213 lg2::info("NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002214 }
2215 else
2216 {
2217 setNmiSource();
2218 }
2219 }
Zev Weiss584aa132021-09-02 19:21:52 -05002220}
2221
Zev Weiss584aa132021-09-02 19:21:52 -05002222static void idButtonHandler(bool state)
2223{
2224 idButtonIface->set_property("ButtonPressed", !state);
2225}
2226
Jason M. Billsfb957332021-01-28 13:18:46 -08002227static void pltRstHandler(bool pltRst)
2228{
2229 if (pltRst)
2230 {
2231 sendPowerControlEvent(Event::pltRstDeAssert);
2232 }
2233 else
2234 {
2235 sendPowerControlEvent(Event::pltRstAssert);
2236 }
2237}
2238
Patrick Williams439b9c32022-07-22 19:26:53 -05002239[[maybe_unused]] static void hostMiscHandler(sdbusplus::message_t& msg)
Jason M. Billsfb957332021-01-28 13:18:46 -08002240{
2241 std::string interfaceName;
2242 boost::container::flat_map<std::string, std::variant<bool>>
2243 propertiesChanged;
Jason M. Billsfb957332021-01-28 13:18:46 -08002244 try
2245 {
2246 msg.read(interfaceName, propertiesChanged);
2247 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002248 catch (const std::exception& e)
Jason M. Billsfb957332021-01-28 13:18:46 -08002249 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002250 lg2::error("Unable to read Host Misc status: {ERROR}", "ERROR", e);
Jason M. Billsfb957332021-01-28 13:18:46 -08002251 return;
2252 }
2253 if (propertiesChanged.empty())
2254 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002255 lg2::error("ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002256 return;
2257 }
2258
2259 for (auto& [property, value] : propertiesChanged)
2260 {
2261 if (property == "ESpiPlatformReset")
2262 {
2263 bool* pltRst = std::get_if<bool>(&value);
2264 if (pltRst == nullptr)
2265 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002266 lg2::error("{PROPERTY} property invalid", "PROPERTY", property);
Jason M. Billsfb957332021-01-28 13:18:46 -08002267 return;
2268 }
2269 pltRstHandler(*pltRst);
2270 }
2271 }
2272}
2273
Zev Weiss584aa132021-09-02 19:21:52 -05002274static void postCompleteHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002275{
Zev Weiss584aa132021-09-02 19:21:52 -05002276 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002277 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002278 sendPowerControlEvent(Event::postCompleteAssert);
Tim Lee86239182021-12-23 11:46:01 +08002279 setOperatingSystemState(OperatingSystemStateStage::Standby);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002280 }
2281 else
2282 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002283 sendPowerControlEvent(Event::postCompleteDeAssert);
Tim Lee86239182021-12-23 11:46:01 +08002284 setOperatingSystemState(OperatingSystemStateStage::Inactive);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002285 }
Zev Weiss584aa132021-09-02 19:21:52 -05002286}
2287
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302288static int loadConfigValues()
2289{
2290 const std::string configFilePath =
2291 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2292 ".json";
2293 std::ifstream configFile(configFilePath.c_str());
2294 if (!configFile.is_open())
2295 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002296 lg2::error("loadConfigValues: Cannot open config path \'{PATH}\'",
2297 "PATH", configFilePath);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302298 return -1;
2299 }
Zev Weiss1aa08b22021-09-15 17:06:20 -05002300 auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302301
Priyatharshan P70120512020-09-16 18:47:20 +05302302 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302303 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002304 lg2::error("Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302305 return -1;
2306 }
Priyatharshan P70120512020-09-16 18:47:20 +05302307 auto gpios = jsonData["gpio_configs"];
2308 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302309
Priyatharshan P70120512020-09-16 18:47:20 +05302310 ConfigData* tempGpioData;
2311
2312 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302313 {
Priyatharshan P70120512020-09-16 18:47:20 +05302314 if (!gpioConfig.contains("Name"))
2315 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002316 lg2::error("The 'Name' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302317 return -1;
2318 }
2319
2320 // Iterate through the powersignal map to check if the gpio json config
2321 // entry is valid
2322 std::string gpioName = gpioConfig["Name"];
2323 auto signalMapIter = powerSignalMap.find(gpioName);
2324 if (signalMapIter == powerSignalMap.end())
2325 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002326 lg2::error(
2327 "{GPIO_NAME} is not a recognized power-control signal name",
2328 "GPIO_NAME", gpioName);
Priyatharshan P70120512020-09-16 18:47:20 +05302329 return -1;
2330 }
2331
2332 // assign the power signal name to the corresponding structure reference
2333 // from map then fillup the structure with coressponding json config
2334 // value
2335 tempGpioData = signalMapIter->second;
2336 tempGpioData->name = gpioName;
2337
2338 if (!gpioConfig.contains("Type"))
2339 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002340 lg2::error("The \'Type\' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302341 return -1;
2342 }
2343
2344 std::string signalType = gpioConfig["Type"];
2345 if (signalType == "GPIO")
2346 {
2347 tempGpioData->type = ConfigType::GPIO;
2348 }
2349 else if (signalType == "DBUS")
2350 {
2351 tempGpioData->type = ConfigType::DBUS;
2352 }
2353 else
2354 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002355 lg2::error("{TYPE} is not a recognized power-control signal type",
2356 "TYPE", signalType);
Priyatharshan P70120512020-09-16 18:47:20 +05302357 return -1;
2358 }
2359
2360 if (tempGpioData->type == ConfigType::GPIO)
2361 {
2362 if (gpioConfig.contains("LineName"))
2363 {
2364 tempGpioData->lineName = gpioConfig["LineName"];
2365 }
2366 else
2367 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002368 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002369 "The \'LineName\' field must be defined for GPIO configuration");
Priyatharshan P70120512020-09-16 18:47:20 +05302370 return -1;
2371 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002372 if (gpioConfig.contains("Polarity"))
2373 {
2374 std::string polarity = gpioConfig["Polarity"];
2375 if (polarity == "ActiveLow")
2376 {
2377 tempGpioData->polarity = false;
2378 }
2379 else if (polarity == "ActiveHigh")
2380 {
2381 tempGpioData->polarity = true;
2382 }
2383 else
2384 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002385 lg2::error(
2386 "Polarity defined but not properly setup. Please only ActiveHigh or ActiveLow. Currently set to {POLARITY}",
2387 "POLARITY", polarity);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002388 return -1;
2389 }
2390 }
2391 else
2392 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002393 lg2::error("Polarity field not found for {GPIO_NAME}",
2394 "GPIO_NAME", tempGpioData->lineName);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002395 return -1;
2396 }
Priyatharshan P70120512020-09-16 18:47:20 +05302397 }
2398 else
2399 {
2400 // if dbus based gpio config is defined read and update the dbus
2401 // params corresponding to the gpio config instance
2402 for (auto& [key, dbusParamName] : dbusParams)
2403 {
Logananth Sundararaja4308042021-10-20 11:52:05 +05302404 if (!gpioConfig.contains(dbusParamName))
Priyatharshan P70120512020-09-16 18:47:20 +05302405 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002406 lg2::error(
2407 "The {DBUS_NAME} field must be defined for Dbus configuration ",
2408 "DBUS_NAME", dbusParamName);
Priyatharshan P70120512020-09-16 18:47:20 +05302409 return -1;
2410 }
2411 }
Logananth Sundararaja4308042021-10-20 11:52:05 +05302412 tempGpioData->dbusName =
2413 gpioConfig[dbusParams[DbusConfigType::name]];
2414 tempGpioData->path = gpioConfig[dbusParams[DbusConfigType::path]];
Priyatharshan P70120512020-09-16 18:47:20 +05302415 tempGpioData->interface =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302416 gpioConfig[dbusParams[DbusConfigType::interface]];
Priyatharshan P70120512020-09-16 18:47:20 +05302417 tempGpioData->lineName =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302418 gpioConfig[dbusParams[DbusConfigType::property]];
Priyatharshan P70120512020-09-16 18:47:20 +05302419 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302420 }
2421
Priyatharshan P70120512020-09-16 18:47:20 +05302422 // read and store the timer values from json config to Timer Map
2423 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302424 {
Priyatharshan P70120512020-09-16 18:47:20 +05302425 if (timers.contains(key.c_str()))
2426 {
2427 timerValue = timers[key.c_str()];
2428 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302429 }
2430
Jonathan Doman891bbde2023-05-17 13:58:24 -07002431 // If "events_configs" key is not in json config, fallback to null
2432 auto events = jsonData.value("event_configs",
2433 nlohmann::json(nlohmann::json::value_t::null));
2434 if (events.is_object())
Olivier FAURAXd7ea2832023-04-14 14:08:02 +00002435 {
2436 nmiWhenPoweredOff = events.value("NMIWhenPoweredOff", true);
2437 }
2438
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302439 return 0;
2440}
Zev Weissa8f116a2021-09-01 21:08:30 -05002441
Patrick Williams439b9c32022-07-22 19:26:53 -05002442static bool getDbusMsgGPIOState(sdbusplus::message_t& msg,
Zev Weissa8f116a2021-09-01 21:08:30 -05002443 const std::string& lineName, bool& value)
2444{
2445 std::string thresholdInterface;
2446 std::string event;
2447 boost::container::flat_map<std::string, std::variant<bool>>
2448 propertiesChanged;
2449 try
2450 {
2451 msg.read(thresholdInterface, propertiesChanged);
2452 if (propertiesChanged.empty())
2453 {
2454 return false;
2455 }
2456
2457 event = propertiesChanged.begin()->first;
2458 if (event.empty() || event != lineName)
2459 {
2460 return false;
2461 }
2462
2463 value = std::get<bool>(propertiesChanged.begin()->second);
2464 return true;
2465 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002466 catch (const std::exception& e)
Zev Weissa8f116a2021-09-01 21:08:30 -05002467 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002468 lg2::error(
2469 "exception while reading dbus property \'{DBUS_NAME}\': {ERROR}",
2470 "DBUS_NAME", lineName, "ERROR", e);
Zev Weissa8f116a2021-09-01 21:08:30 -05002471 return false;
2472 }
2473}
2474
Patrick Williams439b9c32022-07-22 19:26:53 -05002475static sdbusplus::bus::match_t
Zev Weissa8f116a2021-09-01 21:08:30 -05002476 dbusGPIOMatcher(const ConfigData& cfg, std::function<void(bool)> onMatch)
2477{
Patrick Williamsd394c882023-10-20 11:18:44 -05002478 auto pulseEventMatcherCallback = [&cfg,
2479 onMatch](sdbusplus::message_t& msg) {
Patrick Williams439b9c32022-07-22 19:26:53 -05002480 bool value = false;
2481 if (!getDbusMsgGPIOState(msg, cfg.lineName, value))
2482 {
2483 return;
2484 }
2485 onMatch(value);
2486 };
Zev Weissa8f116a2021-09-01 21:08:30 -05002487
Patrick Williams439b9c32022-07-22 19:26:53 -05002488 return sdbusplus::bus::match_t(
2489 static_cast<sdbusplus::bus_t&>(*conn),
Zev Weissa8f116a2021-09-01 21:08:30 -05002490 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2491 "PropertiesChanged',arg0='" +
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302492 cfg.interface + "'",
Zev Weissa8f116a2021-09-01 21:08:30 -05002493 std::move(pulseEventMatcherCallback));
2494}
2495
Michal Orzeledd211e2022-10-28 13:10:16 +02002496// D-Bus property read functions
2497void reschedulePropertyRead(const ConfigData& configData);
Priyatharshan P70120512020-09-16 18:47:20 +05302498
Michal Orzeledd211e2022-10-28 13:10:16 +02002499int getProperty(const ConfigData& configData)
2500{
2501 std::variant<bool> resp;
2502
2503 try
Priyatharshan P70120512020-09-16 18:47:20 +05302504 {
Michal Orzeledd211e2022-10-28 13:10:16 +02002505 auto method = conn->new_method_call(
2506 configData.dbusName.c_str(), configData.path.c_str(),
2507 "org.freedesktop.DBus.Properties", "Get");
2508 method.append(configData.interface.c_str(),
2509 configData.lineName.c_str());
2510
2511 auto reply = conn->call(method);
2512 if (reply.is_method_error())
2513 {
2514 lg2::error(
2515 "Error reading {PROPERTY} D-Bus property on interface {INTERFACE} and path {PATH}",
2516 "PROPERTY", configData.lineName, "INTERFACE",
2517 configData.interface, "PATH", configData.path);
2518 return -1;
2519 }
2520
2521 reply.read(resp);
2522 }
2523 catch (const sdbusplus::exception_t& e)
2524 {
2525 lg2::error("Exception while reading {PROPERTY}: {WHAT}", "PROPERTY",
2526 configData.lineName, "WHAT", e.what());
2527 reschedulePropertyRead(configData);
Priyatharshan P70120512020-09-16 18:47:20 +05302528 return -1;
2529 }
Michal Orzeledd211e2022-10-28 13:10:16 +02002530
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302531 auto respValue = std::get_if<bool>(&resp);
Priyatharshan P70120512020-09-16 18:47:20 +05302532 if (!respValue)
2533 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002534 lg2::error("Error: {PROPERTY} D-Bus property is not the expected type",
2535 "PROPERTY", configData.lineName);
Priyatharshan P70120512020-09-16 18:47:20 +05302536 return -1;
2537 }
2538 return (*respValue);
2539}
Michal Orzeledd211e2022-10-28 13:10:16 +02002540
2541void setInitialValue(const ConfigData& configData, bool initialValue)
2542{
2543 if (configData.name == "PowerOk")
2544 {
2545 powerState = (initialValue ? PowerState::on : PowerState::off);
2546 hostIface->set_property("CurrentHostState",
2547 std::string(getHostState(powerState)));
2548 }
2549 else if (configData.name == "PowerButton")
2550 {
2551 powerButtonIface->set_property("ButtonPressed", !initialValue);
2552 }
2553 else if (configData.name == "ResetButton")
2554 {
2555 resetButtonIface->set_property("ButtonPressed", !initialValue);
2556 }
2557 else if (configData.name == "NMIButton")
2558 {
2559 nmiButtonIface->set_property("ButtonPressed", !initialValue);
2560 }
2561 else if (configData.name == "IdButton")
2562 {
2563 idButtonIface->set_property("ButtonPressed", !initialValue);
2564 }
2565 else if (configData.name == "PostComplete")
2566 {
2567 OperatingSystemStateStage osState =
2568 (initialValue ? OperatingSystemStateStage::Inactive
2569 : OperatingSystemStateStage::Standby);
2570 setOperatingSystemState(osState);
2571 }
2572 else
2573 {
2574 lg2::error("Unknown name {NAME}", "NAME", configData.name);
2575 }
2576}
2577
2578void reschedulePropertyRead(const ConfigData& configData)
2579{
2580 auto item = dBusRetryTimers.find(configData.name);
2581
2582 if (item == dBusRetryTimers.end())
2583 {
2584 auto newItem = dBusRetryTimers.insert(
2585 {configData.name, boost::asio::steady_timer(io)});
2586
2587 if (!newItem.second)
2588 {
2589 lg2::error("Failed to add new timer for {NAME}", "NAME",
2590 configData.name);
2591 return;
2592 }
2593
2594 item = newItem.first;
2595 }
2596
2597 auto& timer = item->second;
2598 timer.expires_after(
2599 std::chrono::milliseconds(TimerMap["DbusGetPropertyRetry"]));
2600 timer.async_wait([&configData](const boost::system::error_code ec) {
2601 if (ec)
2602 {
2603 lg2::error("Retry timer for {NAME} failed: {MSG}", "NAME",
2604 configData.name, "MSG", ec.message());
2605 dBusRetryTimers.erase(configData.name);
2606 return;
2607 }
2608
2609 int property = getProperty(configData);
2610
2611 if (property >= 0)
2612 {
2613 setInitialValue(configData, (property > 0));
2614 dBusRetryTimers.erase(configData.name);
2615 }
2616 });
2617}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002618} // namespace power_control
2619
2620int main(int argc, char* argv[])
2621{
Lei YU92caa4c2021-02-23 16:59:25 +08002622 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05302623
2624 if (argc > 1)
2625 {
2626 node = argv[1];
2627 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002628 lg2::info("Start Chassis power control service for host : {NODE}", "NODE",
2629 node);
Priyatharshan P70120512020-09-16 18:47:20 +05302630
Lei YU92caa4c2021-02-23 16:59:25 +08002631 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002632
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302633 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08002634 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302635 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002636 lg2::error("Host{NODE}: Error in Parsing...", "NODE", node);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302637 }
Naveen Mosesec972d82021-07-16 21:19:23 +05302638 /* Currently for single host based systems additional busname is added
2639 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
2640 Going forward for single hosts the old bus name without zero numbering
2641 will be removed when all other applications adapted to the
2642 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
2643
2644 if (node == "0")
2645 {
2646 // Request all the dbus names
2647 conn->request_name(hostDbusName.c_str());
2648 conn->request_name(chassisDbusName.c_str());
2649 conn->request_name(osDbusName.c_str());
2650 conn->request_name(buttonDbusName.c_str());
2651 conn->request_name(nmiDbusName.c_str());
2652 conn->request_name(rstCauseDbusName.c_str());
2653 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302654
Zev Weissc4005bd2021-09-01 22:30:23 -05002655 hostDbusName += node;
2656 chassisDbusName += node;
2657 osDbusName += node;
2658 buttonDbusName += node;
2659 nmiDbusName += node;
2660 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002661
Priyatharshan P70120512020-09-16 18:47:20 +05302662 // Request all the dbus names
2663 conn->request_name(hostDbusName.c_str());
2664 conn->request_name(chassisDbusName.c_str());
2665 conn->request_name(osDbusName.c_str());
2666 conn->request_name(buttonDbusName.c_str());
2667 conn->request_name(nmiDbusName.c_str());
2668 conn->request_name(rstCauseDbusName.c_str());
2669
2670 if (sioPwrGoodConfig.lineName.empty() ||
2671 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05302672 {
Lei YU92caa4c2021-02-23 16:59:25 +08002673 sioEnabled = false;
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002674 lg2::info("SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05302675 }
2676
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002677 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302678 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002679 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002680 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302681 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302682 {
2683 return -1;
2684 }
2685 }
Priyatharshan P70120512020-09-16 18:47:20 +05302686 else if (powerOkConfig.type == ConfigType::DBUS)
2687 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002688 static sdbusplus::bus::match_t powerOkEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002689 power_control::dbusGPIOMatcher(powerOkConfig, psPowerOKHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302690 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302691 else
2692 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002693 lg2::error("PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002694 return -1;
2695 }
2696
Lei YU92caa4c2021-02-23 16:59:25 +08002697 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002698 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05302699 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302700 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302701 {
Priyatharshan P70120512020-09-16 18:47:20 +05302702 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002703 sioPowerGoodHandler, sioPowerGoodLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302704 sioPowerGoodEvent))
2705 {
2706 return -1;
2707 }
2708 }
2709 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
2710 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002711 static sdbusplus::bus::match_t sioPwrGoodEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002712 power_control::dbusGPIOMatcher(sioPwrGoodConfig,
2713 sioPowerGoodHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302714 }
2715 else
2716 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002717 lg2::error(
Priyatharshan P70120512020-09-16 18:47:20 +05302718 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302719 return -1;
2720 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002721
Priyatharshan P19c47a32020-08-12 18:16:43 +05302722 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302723 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302724 {
Priyatharshan P70120512020-09-16 18:47:20 +05302725 if (!requestGPIOEvents(sioOnControlConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002726 sioOnControlHandler, sioOnControlLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302727 sioOnControlEvent))
2728 {
2729 return -1;
2730 }
2731 }
2732 else if (sioOnControlConfig.type == ConfigType::DBUS)
2733 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002734 static sdbusplus::bus::match_t sioOnControlEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002735 power_control::dbusGPIOMatcher(sioOnControlConfig,
2736 sioOnControlHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302737 }
2738 else
2739 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002740 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002741 "sioOnControl name should be configured from jsonconfig file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302742 return -1;
2743 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002744
Priyatharshan P19c47a32020-08-12 18:16:43 +05302745 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302746 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302747 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002748 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
Priyatharshan P70120512020-09-16 18:47:20 +05302749 sioS5Line, sioS5Event))
2750 {
2751 return -1;
2752 }
2753 }
2754 else if (sioS5Config.type == ConfigType::DBUS)
2755 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002756 static sdbusplus::bus::match_t sioS5EventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002757 power_control::dbusGPIOMatcher(sioS5Config, sioS5Handler);
Priyatharshan P70120512020-09-16 18:47:20 +05302758 }
2759 else
2760 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002761 lg2::error("sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302762 return -1;
2763 }
2764 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002765
2766 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302767 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002768 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002769 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
2770 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302771 {
2772 return -1;
2773 }
2774 }
Priyatharshan P70120512020-09-16 18:47:20 +05302775 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302776 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002777 static sdbusplus::bus::match_t powerButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002778 power_control::dbusGPIOMatcher(powerButtonConfig,
2779 powerButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002780 }
2781
2782 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302783 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002784 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002785 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
2786 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302787 {
2788 return -1;
2789 }
2790 }
Priyatharshan P70120512020-09-16 18:47:20 +05302791 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302792 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002793 static sdbusplus::bus::match_t resetButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002794 power_control::dbusGPIOMatcher(resetButtonConfig,
2795 resetButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002796 }
2797
2798 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302799 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302800 {
Priyatharshan P70120512020-09-16 18:47:20 +05302801 if (!nmiButtonConfig.lineName.empty())
2802 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002803 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302804 nmiButtonLine, nmiButtonEvent);
2805 }
2806 }
2807 else if (nmiButtonConfig.type == ConfigType::DBUS)
2808 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002809 static sdbusplus::bus::match_t nmiButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002810 power_control::dbusGPIOMatcher(nmiButtonConfig, nmiButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302811 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002812
2813 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302814 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302815 {
Priyatharshan P70120512020-09-16 18:47:20 +05302816 if (!idButtonConfig.lineName.empty())
2817 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002818 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302819 idButtonLine, idButtonEvent);
2820 }
2821 }
2822 else if (idButtonConfig.type == ConfigType::DBUS)
2823 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002824 static sdbusplus::bus::match_t idButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002825 power_control::dbusGPIOMatcher(idButtonConfig, idButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302826 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002827
Jason M. Billsfb957332021-01-28 13:18:46 -08002828#ifdef USE_PLT_RST
Patrick Williams439b9c32022-07-22 19:26:53 -05002829 sdbusplus::bus::match_t pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08002830 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08002831 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2832 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08002833 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08002834#endif
2835
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002836 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302837 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002838 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002839 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
2840 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302841 {
2842 return -1;
2843 }
2844 }
Priyatharshan P70120512020-09-16 18:47:20 +05302845 else if (postCompleteConfig.type == ConfigType::DBUS)
2846 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002847 static sdbusplus::bus::match_t postCompleteEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002848 power_control::dbusGPIOMatcher(postCompleteConfig,
2849 postCompleteHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302850 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302851 else
2852 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002853 lg2::error(
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002854 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002855 return -1;
2856 }
2857
2858 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05302859 if (!nmiOutConfig.lineName.empty())
2860 {
Jian Zhang461a1662022-09-22 11:29:01 +08002861 setGPIOOutput(nmiOutConfig.lineName, !nmiOutConfig.polarity,
2862 nmiOutLine);
Priyatharshan P70120512020-09-16 18:47:20 +05302863 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002864
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002865 // Initialize POWER_OUT and RESET_OUT GPIO.
2866 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05302867 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002868 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002869 if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
2870 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302871 {
2872 return -1;
2873 }
2874 }
2875 else
2876 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002877 lg2::error("powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002878 return -1;
2879 }
2880
Priyatharshan P70120512020-09-16 18:47:20 +05302881 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002882 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002883 if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
2884 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302885 {
2886 return -1;
2887 }
2888 }
2889 else
2890 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002891 lg2::error("ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002892 return -1;
2893 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002894 // Release line
2895 line.reset();
2896
Matt Simmering58e379d2022-09-23 14:45:50 -07002897 // Initialize the power state and operating system state
Lei YU92caa4c2021-02-23 16:59:25 +08002898 powerState = PowerState::off;
Matt Simmering58e379d2022-09-23 14:45:50 -07002899 operatingSystemState = OperatingSystemStateStage::Inactive;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002900 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05302901
2902 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002903 {
Jean-Marie Verdun61b4a5b2021-09-19 08:53:28 -04002904 if (psPowerOKLine.get_value() > 0 ||
Lei YUa37c2472021-09-26 15:57:12 +08002905 (sioEnabled &&
2906 (sioPowerGoodLine.get_value() == sioPwrGoodConfig.polarity)))
Priyatharshan P70120512020-09-16 18:47:20 +05302907 {
2908 powerState = PowerState::on;
2909 }
2910 }
2911 else
2912 {
2913 if (getProperty(powerOkConfig))
2914 {
2915 powerState = PowerState::on;
2916 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002917 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002918 // Check if we need to start the Power Restore policy
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03002919 if (powerState != PowerState::on)
2920 {
2921 powerRestore.run();
2922 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002923
Lei YU92caa4c2021-02-23 16:59:25 +08002924 if (nmiOutLine)
2925 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002926
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002927 lg2::info("Initializing power state.");
Lei YU92caa4c2021-02-23 16:59:25 +08002928 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002929
2930 // Power Control Service
2931 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002932 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002933
2934 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05302935 hostIface =
2936 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
2937 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002938 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08002939 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002940 "RequestedHostTransition",
2941 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2942 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002943 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2944 {
2945 // if power button is masked, ignore this
2946 if (!powerButtonMask)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002947 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002948 sendPowerControlEvent(Event::gracefulPowerOffRequest);
2949 addRestartCause(RestartCause::command);
Jason M. Billse7520ba2020-01-31 11:19:03 -08002950 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002951 else
2952 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002953 lg2::info("Power Button Masked.");
2954 throw std::invalid_argument("Transition Request Masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002955 return 0;
2956 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05002957 }
2958 else if (requested == "xyz.openbmc_project.State.Host.Transition.On")
2959 {
2960 // if power button is masked, ignore this
2961 if (!powerButtonMask)
2962 {
2963 sendPowerControlEvent(Event::powerOnRequest);
2964 addRestartCause(RestartCause::command);
2965 }
2966 else
2967 {
2968 lg2::info("Power Button Masked.");
2969 throw std::invalid_argument("Transition Request Masked");
2970 return 0;
2971 }
2972 }
2973 else if (requested ==
2974 "xyz.openbmc_project.State.Host.Transition.Reboot")
2975 {
2976 // if power button is masked, ignore this
2977 if (!powerButtonMask)
2978 {
2979 sendPowerControlEvent(Event::powerCycleRequest);
2980 addRestartCause(RestartCause::command);
2981 }
2982 else
2983 {
2984 lg2::info("Power Button Masked.");
2985 throw std::invalid_argument("Transition Request Masked");
2986 return 0;
2987 }
2988 }
2989 else if (requested ==
2990 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot")
2991 {
2992 // if reset button is masked, ignore this
2993 if (!resetButtonMask)
2994 {
2995 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
2996 addRestartCause(RestartCause::command);
2997 }
2998 else
2999 {
3000 lg2::info("Reset Button Masked.");
3001 throw std::invalid_argument("Transition Request Masked");
3002 return 0;
3003 }
3004 }
3005 else if (requested ==
3006 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot")
3007 {
3008 // if reset button is masked, ignore this
3009 if (!resetButtonMask)
3010 {
3011 sendPowerControlEvent(Event::resetRequest);
3012 addRestartCause(RestartCause::command);
3013 }
3014 else
3015 {
3016 lg2::info("Reset Button Masked.");
3017 throw std::invalid_argument("Transition Request Masked");
3018 return 0;
3019 }
3020 }
3021 else
3022 {
3023 lg2::error("Unrecognized host state transition request.");
3024 throw std::invalid_argument("Unrecognized Transition Request");
3025 return 0;
3026 }
3027 resp = requested;
3028 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003029 });
Lei YU92caa4c2021-02-23 16:59:25 +08003030 hostIface->register_property("CurrentHostState",
3031 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003032
Lei YU92caa4c2021-02-23 16:59:25 +08003033 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003034
3035 // Chassis Control Service
3036 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003037 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003038
3039 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003040 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05303041 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003042 "xyz.openbmc_project.State.Chassis");
3043
Lei YU92caa4c2021-02-23 16:59:25 +08003044 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003045 "RequestedPowerTransition",
3046 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
3047 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003048 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
3049 {
3050 // if power button is masked, ignore this
3051 if (!powerButtonMask)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003052 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003053 sendPowerControlEvent(Event::powerOffRequest);
3054 addRestartCause(RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003055 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003056 else
3057 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003058 lg2::info("Power Button Masked.");
3059 throw std::invalid_argument("Transition Request Masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003060 return 0;
3061 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003062 }
3063 else if (requested == "xyz.openbmc_project.State.Chassis.Transition.On")
3064 {
3065 // if power button is masked, ignore this
3066 if (!powerButtonMask)
3067 {
3068 sendPowerControlEvent(Event::powerOnRequest);
3069 addRestartCause(RestartCause::command);
3070 }
3071 else
3072 {
3073 lg2::info("Power Button Masked.");
3074 throw std::invalid_argument("Transition Request Masked");
3075 return 0;
3076 }
3077 }
3078 else if (requested ==
3079 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3080 {
3081 // if power button is masked, ignore this
3082 if (!powerButtonMask)
3083 {
3084 sendPowerControlEvent(Event::powerCycleRequest);
3085 addRestartCause(RestartCause::command);
3086 }
3087 else
3088 {
3089 lg2::info("Power Button Masked.");
3090 throw std::invalid_argument("Transition Request Masked");
3091 return 0;
3092 }
3093 }
3094 else
3095 {
3096 lg2::error("Unrecognized chassis state transition request.");
3097 throw std::invalid_argument("Unrecognized Transition Request");
3098 return 0;
3099 }
3100 resp = requested;
3101 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003102 });
Lei YU92caa4c2021-02-23 16:59:25 +08003103 chassisIface->register_property("CurrentPowerState",
3104 std::string(getChassisState(powerState)));
3105 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003106
Lei YU92caa4c2021-02-23 16:59:25 +08003107 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003108
Vijay Khemka04175c22020-10-09 14:28:11 -07003109#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003110 // Chassis System Service
3111 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003112 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003113
3114 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003115 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003116 "/xyz/openbmc_project/state/chassis_system0",
3117 "xyz.openbmc_project.State.Chassis");
3118
Lei YU92caa4c2021-02-23 16:59:25 +08003119 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003120 "RequestedPowerTransition",
3121 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3122 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003123 if (requested ==
3124 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3125 {
3126 systemReset();
3127 addRestartCause(RestartCause::command);
3128 }
3129 else
3130 {
3131 lg2::error("Unrecognized chassis system state transition request.");
3132 throw std::invalid_argument("Unrecognized Transition Request");
3133 return 0;
3134 }
3135 resp = requested;
3136 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003137 });
Lei YU92caa4c2021-02-23 16:59:25 +08003138 chassisSysIface->register_property(
3139 "CurrentPowerState", std::string(getChassisState(powerState)));
3140 chassisSysIface->register_property("LastStateChangeTime",
3141 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003142
Lei YU92caa4c2021-02-23 16:59:25 +08003143 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003144
Naveen Moses117c34e2021-05-26 20:10:51 +05303145 if (!slotPowerConfig.lineName.empty())
3146 {
3147 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3148 {
3149 return -1;
3150 }
3151
3152 slotPowerState = SlotPowerState::off;
3153 if (slotPowerLine.get_value() > 0)
3154 {
3155 slotPowerState = SlotPowerState::on;
3156 }
3157
3158 chassisSlotIface = chassisSysServer.add_interface(
3159 "/xyz/openbmc_project/state/chassis_system" + node,
3160 "xyz.openbmc_project.State.Chassis");
3161 chassisSlotIface->register_property(
3162 "RequestedPowerTransition",
3163 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3164 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003165 if (requested == "xyz.openbmc_project.State.Chassis.Transition.On")
3166 {
3167 slotPowerOn();
3168 }
3169 else if (requested ==
3170 "xyz.openbmc_project.State.Chassis.Transition.Off")
3171 {
3172 slotPowerOff();
3173 }
3174 else if (requested ==
3175 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3176 {
3177 slotPowerCycle();
3178 }
3179 else
3180 {
3181 lg2::error(
3182 "Unrecognized chassis system state transition request.\n");
3183 throw std::invalid_argument("Unrecognized Transition Request");
3184 return 0;
3185 }
3186 resp = requested;
3187 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003188 });
Naveen Moses117c34e2021-05-26 20:10:51 +05303189 chassisSlotIface->register_property(
3190 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3191 chassisSlotIface->register_property("LastStateChangeTime",
3192 getCurrentTimeMs());
3193 chassisSlotIface->initialize();
3194 }
3195#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003196 // Buttons Service
3197 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003198 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003199
Priyatharshan P70120512020-09-16 18:47:20 +05303200 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003201 {
Priyatharshan P70120512020-09-16 18:47:20 +05303202 // Power Button Interface
3203 power_control::powerButtonIface = buttonsServer.add_interface(
3204 "/xyz/openbmc_project/chassis/buttons/power",
3205 "xyz.openbmc_project.Chassis.Buttons");
3206
3207 powerButtonIface->register_property(
Patrick Williamsd394c882023-10-20 11:18:44 -05003208 "ButtonMasked", false, [](const bool requested, bool& current) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003209 if (requested)
3210 {
3211 if (powerButtonMask)
Priyatharshan P70120512020-09-16 18:47:20 +05303212 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003213 return 1;
Priyatharshan P70120512020-09-16 18:47:20 +05303214 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003215 if (!setGPIOOutput(powerOutConfig.lineName,
3216 !powerOutConfig.polarity, powerButtonMask))
Priyatharshan P70120512020-09-16 18:47:20 +05303217 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003218 throw std::runtime_error("Failed to request GPIO");
3219 return 0;
Priyatharshan P70120512020-09-16 18:47:20 +05303220 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003221 lg2::info("Power Button Masked.");
3222 }
3223 else
3224 {
3225 if (!powerButtonMask)
3226 {
3227 return 1;
3228 }
3229 lg2::info("Power Button Un-masked");
3230 powerButtonMask.reset();
3231 }
3232 // Update the mask setting
3233 current = requested;
3234 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003235 });
Priyatharshan P70120512020-09-16 18:47:20 +05303236
3237 // Check power button state
3238 bool powerButtonPressed;
3239 if (powerButtonConfig.type == ConfigType::GPIO)
3240 {
3241 powerButtonPressed = powerButtonLine.get_value() == 0;
3242 }
3243 else
3244 {
3245 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3246 }
3247
3248 powerButtonIface->register_property("ButtonPressed",
3249 powerButtonPressed);
3250
3251 powerButtonIface->initialize();
3252 }
3253
3254 if (!resetButtonConfig.lineName.empty())
3255 {
3256 // Reset Button Interface
3257
Lei YU92caa4c2021-02-23 16:59:25 +08003258 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003259 "/xyz/openbmc_project/chassis/buttons/reset",
3260 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003261
Lei YU92caa4c2021-02-23 16:59:25 +08003262 resetButtonIface->register_property(
Patrick Williamsd394c882023-10-20 11:18:44 -05003263 "ButtonMasked", false, [](const bool requested, bool& current) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003264 if (requested)
3265 {
3266 if (resetButtonMask)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003267 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003268 return 1;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003269 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003270 if (!setGPIOOutput(resetOutConfig.lineName,
3271 !resetOutConfig.polarity, resetButtonMask))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003272 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003273 throw std::runtime_error("Failed to request GPIO");
3274 return 0;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003275 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003276 lg2::info("Reset Button Masked.");
3277 }
3278 else
3279 {
3280 if (!resetButtonMask)
3281 {
3282 return 1;
3283 }
3284 lg2::info("Reset Button Un-masked");
3285 resetButtonMask.reset();
3286 }
3287 // Update the mask setting
3288 current = requested;
3289 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003290 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003291
John Wang6c090072020-09-30 13:32:16 +08003292 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303293 bool resetButtonPressed;
3294 if (resetButtonConfig.type == ConfigType::GPIO)
3295 {
3296 resetButtonPressed = resetButtonLine.get_value() == 0;
3297 }
3298 else
3299 {
3300 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3301 }
3302
Lei YU92caa4c2021-02-23 16:59:25 +08003303 resetButtonIface->register_property("ButtonPressed",
3304 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003305
Lei YU92caa4c2021-02-23 16:59:25 +08003306 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003307 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003308
Lei YU92caa4c2021-02-23 16:59:25 +08003309 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003310 {
3311 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003312 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003313 "/xyz/openbmc_project/chassis/buttons/nmi",
3314 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003315
Lei YU92caa4c2021-02-23 16:59:25 +08003316 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003317 "ButtonMasked", false, [](const bool requested, bool& current) {
Patrick Williamsd394c882023-10-20 11:18:44 -05003318 if (nmiButtonMasked == requested)
3319 {
3320 // NMI button mask is already set as requested, so no change
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003321 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003322 }
3323 if (requested)
3324 {
3325 lg2::info("NMI Button Masked.");
3326 nmiButtonMasked = true;
3327 }
3328 else
3329 {
3330 lg2::info("NMI Button Un-masked.");
3331 nmiButtonMasked = false;
3332 }
3333 // Update the mask setting
3334 current = nmiButtonMasked;
3335 return 1;
3336 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003337
Vijay Khemka33a532d2019-11-14 16:50:35 -08003338 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303339 bool nmiButtonPressed;
3340 if (nmiButtonConfig.type == ConfigType::GPIO)
3341 {
3342 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3343 }
3344 else
3345 {
3346 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3347 }
3348
Lei YU92caa4c2021-02-23 16:59:25 +08003349 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003350
Lei YU92caa4c2021-02-23 16:59:25 +08003351 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003352 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003353
Lei YU92caa4c2021-02-23 16:59:25 +08003354 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003355 {
3356 // NMI out Service
3357 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003358 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003359
Vijay Khemka33a532d2019-11-14 16:50:35 -08003360 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303361 nmiOutIface = nmiOutServer.add_interface(
3362 "/xyz/openbmc_project/control/host" + node + "/nmi",
3363 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003364 nmiOutIface->register_method("NMI", nmiReset);
3365 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003366 }
Chen Yugang174ec662019-08-19 19:58:49 +08003367
Lei YU92caa4c2021-02-23 16:59:25 +08003368 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003369 {
3370 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003371 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003372 "/xyz/openbmc_project/chassis/buttons/id",
3373 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003374
Vijay Khemka33a532d2019-11-14 16:50:35 -08003375 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303376 bool idButtonPressed;
3377 if (idButtonConfig.type == ConfigType::GPIO)
3378 {
3379 idButtonPressed = idButtonLine.get_value() == 0;
3380 }
3381 else
3382 {
3383 idButtonPressed = getProperty(idButtonConfig) == 0;
3384 }
3385
Lei YU92caa4c2021-02-23 16:59:25 +08003386 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003387
Lei YU92caa4c2021-02-23 16:59:25 +08003388 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003389 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003390
3391 // OS State Service
3392 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003393 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003394
3395 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003396 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003397 "/xyz/openbmc_project/state/os",
3398 "xyz.openbmc_project.State.OperatingSystem.Status");
3399
3400 // Get the initial OS state based on POST complete
3401 // 0: Asserted, OS state is "Standby" (ready to boot)
3402 // 1: De-Asserted, OS state is "Inactive"
Tim Lee86239182021-12-23 11:46:01 +08003403 OperatingSystemStateStage osState;
Priyatharshan P70120512020-09-16 18:47:20 +05303404 if (postCompleteConfig.type == ConfigType::GPIO)
3405 {
Tim Lee86239182021-12-23 11:46:01 +08003406 osState = postCompleteLine.get_value() > 0
3407 ? OperatingSystemStateStage::Inactive
3408 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303409 }
3410 else
3411 {
Tim Lee86239182021-12-23 11:46:01 +08003412 osState = getProperty(postCompleteConfig) > 0
3413 ? OperatingSystemStateStage::Inactive
3414 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303415 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003416
Tim Lee86239182021-12-23 11:46:01 +08003417 osIface->register_property(
3418 "OperatingSystemState",
3419 std::string(getOperatingSystemStateStage(osState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003420
Lei YU92caa4c2021-02-23 16:59:25 +08003421 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003422
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003423 // Restart Cause Service
3424 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003425 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003426
3427 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003428 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303429 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003430 "xyz.openbmc_project.Control.Host.RestartCause");
3431
Lei YU92caa4c2021-02-23 16:59:25 +08003432 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003433 "RestartCause",
3434 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3435
Lei YU92caa4c2021-02-23 16:59:25 +08003436 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003437 "RequestedRestartCause",
3438 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3439 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003440 if (requested ==
3441 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3442 {
3443 addRestartCause(RestartCause::watchdog);
3444 }
3445 else
3446 {
3447 throw std::invalid_argument("Unrecognized RestartCause Request");
3448 return 0;
3449 }
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003450
Patrick Williams48aa1f02023-05-10 07:50:30 -05003451 lg2::info("RestartCause requested: {RESTART_CAUSE}", "RESTART_CAUSE",
3452 requested);
3453 resp = requested;
3454 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003455 });
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003456
Lei YU92caa4c2021-02-23 16:59:25 +08003457 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003458
Lei YU92caa4c2021-02-23 16:59:25 +08003459 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003460
Lei YU92caa4c2021-02-23 16:59:25 +08003461 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003462
3463 return 0;
3464}