blob: 07fc14f9d58156caa353136fba9792a97ed0f156 [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},
145 {"SlotPowerCycleMs", 200}};
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700146
147static bool nmiEnabled = true;
Olivier FAURAXd7ea2832023-04-14 14:08:02 +0000148static bool nmiWhenPoweredOff = true;
Priyatharshan P19c47a32020-08-12 18:16:43 +0530149static bool sioEnabled = true;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700150
151// Timers
152// Time holding GPIOs asserted
153static boost::asio::steady_timer gpioAssertTimer(io);
154// Time between off and on during a power cycle
155static boost::asio::steady_timer powerCycleTimer(io);
156// Time OS gracefully powering off
157static boost::asio::steady_timer gracefulPowerOffTimer(io);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700158// Time the warm reset check
159static boost::asio::steady_timer warmResetCheckTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700160// Time power supply power OK assertion on power-on
161static boost::asio::steady_timer psPowerOKWatchdogTimer(io);
162// Time SIO power good assertion on power-on
163static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io);
164// Time power-off state save for power loss tracking
165static boost::asio::steady_timer powerStateSaveTimer(io);
166// POH timer
167static boost::asio::steady_timer pohCounterTimer(io);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700168// Time when to allow restart cause updates
169static boost::asio::steady_timer restartCauseTimer(io);
Naveen Moses117c34e2021-05-26 20:10:51 +0530170static boost::asio::steady_timer slotPowerCycleTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700171
172// GPIO Lines and Event Descriptors
173static gpiod::line psPowerOKLine;
174static boost::asio::posix::stream_descriptor psPowerOKEvent(io);
175static gpiod::line sioPowerGoodLine;
176static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io);
177static gpiod::line sioOnControlLine;
178static boost::asio::posix::stream_descriptor sioOnControlEvent(io);
179static gpiod::line sioS5Line;
180static boost::asio::posix::stream_descriptor sioS5Event(io);
181static gpiod::line powerButtonLine;
182static boost::asio::posix::stream_descriptor powerButtonEvent(io);
183static gpiod::line resetButtonLine;
184static boost::asio::posix::stream_descriptor resetButtonEvent(io);
185static gpiod::line nmiButtonLine;
186static boost::asio::posix::stream_descriptor nmiButtonEvent(io);
187static gpiod::line idButtonLine;
188static boost::asio::posix::stream_descriptor idButtonEvent(io);
189static gpiod::line postCompleteLine;
190static boost::asio::posix::stream_descriptor postCompleteEvent(io);
191static gpiod::line nmiOutLine;
Naveen Moses117c34e2021-05-26 20:10:51 +0530192static gpiod::line slotPowerLine;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700193
194static constexpr uint8_t beepPowerFail = 8;
195
196static void beep(const uint8_t& beepPriority)
197{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800198 lg2::info("Beep with priority: {BEEP_PRIORITY}", "BEEP_PRIORITY",
199 beepPriority);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700200
201 conn->async_method_call(
202 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -0500203 if (ec)
204 {
205 lg2::error(
206 "beep returned error with async_method_call (ec = {ERROR_MSG})",
207 "ERROR_MSG", ec.message());
208 return;
209 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700210 },
211 "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
212 "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
213}
214
Tim Lee86239182021-12-23 11:46:01 +0800215enum class OperatingSystemStateStage
216{
217 Inactive,
218 Standby,
219};
Matt Simmering58e379d2022-09-23 14:45:50 -0700220static OperatingSystemStateStage operatingSystemState;
Tim Lee86239182021-12-23 11:46:01 +0800221static constexpr std::string_view
222 getOperatingSystemStateStage(const OperatingSystemStateStage stage)
223{
224 switch (stage)
225 {
226 case OperatingSystemStateStage::Inactive:
227 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
228 break;
229 case OperatingSystemStateStage::Standby:
230 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Standby";
231 break;
232 default:
233 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
234 break;
235 }
236};
237static void setOperatingSystemState(const OperatingSystemStateStage stage)
238{
Matt Simmering58e379d2022-09-23 14:45:50 -0700239 operatingSystemState = stage;
240#if IGNORE_SOFT_RESETS_DURING_POST
241 // If POST complete has asserted set ignoreNextSoftReset to false to avoid
242 // masking soft resets after POST
243 if (operatingSystemState == OperatingSystemStateStage::Standby)
244 {
245 ignoreNextSoftReset = false;
246 }
247#endif
Tim Lee86239182021-12-23 11:46:01 +0800248 osIface->set_property("OperatingSystemState",
249 std::string(getOperatingSystemStateStage(stage)));
250
251 lg2::info("Moving os state to {STATE} stage", "STATE",
252 getOperatingSystemStateStage(stage));
253}
254
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700255enum class PowerState
256{
257 on,
258 waitForPSPowerOK,
259 waitForSIOPowerGood,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700260 off,
261 transitionToOff,
262 gracefulTransitionToOff,
263 cycleOff,
264 transitionToCycleOff,
265 gracefulTransitionToCycleOff,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700266 checkForWarmReset,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700267};
268static PowerState powerState;
269static std::string getPowerStateName(PowerState state)
270{
271 switch (state)
272 {
273 case PowerState::on:
274 return "On";
275 break;
276 case PowerState::waitForPSPowerOK:
277 return "Wait for Power Supply Power OK";
278 break;
279 case PowerState::waitForSIOPowerGood:
280 return "Wait for SIO Power Good";
281 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700282 case PowerState::off:
283 return "Off";
284 break;
285 case PowerState::transitionToOff:
286 return "Transition to Off";
287 break;
288 case PowerState::gracefulTransitionToOff:
289 return "Graceful Transition to Off";
290 break;
291 case PowerState::cycleOff:
292 return "Power Cycle Off";
293 break;
294 case PowerState::transitionToCycleOff:
295 return "Transition to Power Cycle Off";
296 break;
297 case PowerState::gracefulTransitionToCycleOff:
298 return "Graceful Transition to Power Cycle Off";
299 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700300 case PowerState::checkForWarmReset:
301 return "Check for Warm Reset";
302 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700303 default:
304 return "unknown state: " + std::to_string(static_cast<int>(state));
305 break;
306 }
307}
308static void logStateTransition(const PowerState state)
309{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800310 lg2::info("Host{HOST}: Moving to \"{STATE}\" state", "HOST", node, "STATE",
311 getPowerStateName(state));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700312}
313
314enum class Event
315{
316 psPowerOKAssert,
317 psPowerOKDeAssert,
318 sioPowerGoodAssert,
319 sioPowerGoodDeAssert,
320 sioS5Assert,
321 sioS5DeAssert,
Jason M. Billsfb957332021-01-28 13:18:46 -0800322 pltRstAssert,
323 pltRstDeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700324 postCompleteAssert,
325 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700326 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700327 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700328 powerCycleTimerExpired,
329 psPowerOKWatchdogTimerExpired,
330 sioPowerGoodWatchdogTimerExpired,
331 gracefulPowerOffTimerExpired,
332 powerOnRequest,
333 powerOffRequest,
334 powerCycleRequest,
335 resetRequest,
336 gracefulPowerOffRequest,
337 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700338 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700339};
340static std::string getEventName(Event event)
341{
342 switch (event)
343 {
344 case Event::psPowerOKAssert:
345 return "power supply power OK assert";
346 break;
347 case Event::psPowerOKDeAssert:
348 return "power supply power OK de-assert";
349 break;
350 case Event::sioPowerGoodAssert:
351 return "SIO power good assert";
352 break;
353 case Event::sioPowerGoodDeAssert:
354 return "SIO power good de-assert";
355 break;
356 case Event::sioS5Assert:
357 return "SIO S5 assert";
358 break;
359 case Event::sioS5DeAssert:
360 return "SIO S5 de-assert";
361 break;
Jason M. Billsfb957332021-01-28 13:18:46 -0800362 case Event::pltRstAssert:
363 return "PLT_RST assert";
364 break;
365 case Event::pltRstDeAssert:
366 return "PLT_RST de-assert";
367 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700368 case Event::postCompleteAssert:
369 return "POST Complete assert";
370 break;
371 case Event::postCompleteDeAssert:
372 return "POST Complete de-assert";
373 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700374 case Event::powerButtonPressed:
375 return "power button pressed";
376 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700377 case Event::resetButtonPressed:
378 return "reset button pressed";
379 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700380 case Event::powerCycleTimerExpired:
381 return "power cycle timer expired";
382 break;
383 case Event::psPowerOKWatchdogTimerExpired:
384 return "power supply power OK watchdog timer expired";
385 break;
386 case Event::sioPowerGoodWatchdogTimerExpired:
387 return "SIO power good watchdog timer expired";
388 break;
389 case Event::gracefulPowerOffTimerExpired:
390 return "graceful power-off timer expired";
391 break;
392 case Event::powerOnRequest:
393 return "power-on request";
394 break;
395 case Event::powerOffRequest:
396 return "power-off request";
397 break;
398 case Event::powerCycleRequest:
399 return "power-cycle request";
400 break;
401 case Event::resetRequest:
402 return "reset request";
403 break;
404 case Event::gracefulPowerOffRequest:
405 return "graceful power-off request";
406 break;
407 case Event::gracefulPowerCycleRequest:
408 return "graceful power-cycle request";
409 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700410 case Event::warmResetDetected:
411 return "warm reset detected";
412 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700413 default:
414 return "unknown event: " + std::to_string(static_cast<int>(event));
415 break;
416 }
417}
418static void logEvent(const std::string_view stateHandler, const Event event)
419{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800420 lg2::info("{STATE_HANDLER}: {EVENT} event received", "STATE_HANDLER",
421 stateHandler, "EVENT", getEventName(event));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700422}
423
424// Power state handlers
425static void powerStateOn(const Event event);
426static void powerStateWaitForPSPowerOK(const Event event);
427static void powerStateWaitForSIOPowerGood(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700428static void powerStateOff(const Event event);
429static void powerStateTransitionToOff(const Event event);
430static void powerStateGracefulTransitionToOff(const Event event);
431static void powerStateCycleOff(const Event event);
432static void powerStateTransitionToCycleOff(const Event event);
433static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700434static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700435
436static std::function<void(const Event)> getPowerStateHandler(PowerState state)
437{
438 switch (state)
439 {
440 case PowerState::on:
441 return powerStateOn;
442 break;
443 case PowerState::waitForPSPowerOK:
444 return powerStateWaitForPSPowerOK;
445 break;
446 case PowerState::waitForSIOPowerGood:
447 return powerStateWaitForSIOPowerGood;
448 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700449 case PowerState::off:
450 return powerStateOff;
451 break;
452 case PowerState::transitionToOff:
453 return powerStateTransitionToOff;
454 break;
455 case PowerState::gracefulTransitionToOff:
456 return powerStateGracefulTransitionToOff;
457 break;
458 case PowerState::cycleOff:
459 return powerStateCycleOff;
460 break;
461 case PowerState::transitionToCycleOff:
462 return powerStateTransitionToCycleOff;
463 break;
464 case PowerState::gracefulTransitionToCycleOff:
465 return powerStateGracefulTransitionToCycleOff;
466 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700467 case PowerState::checkForWarmReset:
468 return powerStateCheckForWarmReset;
469 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700470 default:
Zev Weiss047bcb52020-08-20 21:28:11 +0000471 return nullptr;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700472 break;
473 }
474};
475
476static void sendPowerControlEvent(const Event event)
477{
478 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
479 if (handler == nullptr)
480 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800481 lg2::error("Failed to find handler for power state: {STATE}", "STATE",
482 static_cast<int>(powerState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700483 return;
484 }
485 handler(event);
486}
487
488static uint64_t getCurrentTimeMs()
489{
490 struct timespec time = {};
491
492 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
493 {
494 return 0;
495 }
496 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
497 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
498
499 return currentTimeMs;
500}
501
502static constexpr std::string_view getHostState(const PowerState state)
503{
504 switch (state)
505 {
506 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700507 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700508 case PowerState::gracefulTransitionToCycleOff:
509 return "xyz.openbmc_project.State.Host.HostState.Running";
510 break;
511 case PowerState::waitForPSPowerOK:
512 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700513 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700514 case PowerState::transitionToOff:
515 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700516 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700517 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700518 return "xyz.openbmc_project.State.Host.HostState.Off";
519 break;
520 default:
521 return "";
522 break;
523 }
524};
525static constexpr std::string_view getChassisState(const PowerState state)
526{
527 switch (state)
528 {
529 case PowerState::on:
530 case PowerState::transitionToOff:
531 case PowerState::gracefulTransitionToOff:
532 case PowerState::transitionToCycleOff:
533 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700534 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700535 return "xyz.openbmc_project.State.Chassis.PowerState.On";
536 break;
537 case PowerState::waitForPSPowerOK:
538 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700539 case PowerState::off:
540 case PowerState::cycleOff:
541 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
542 break;
543 default:
544 return "";
545 break;
546 }
547};
Naveen Moses117c34e2021-05-26 20:10:51 +0530548#ifdef CHASSIS_SYSTEM_RESET
549enum class SlotPowerState
550{
551 on,
552 off,
553};
554static SlotPowerState slotPowerState;
555static constexpr std::string_view getSlotState(const SlotPowerState state)
556{
557 switch (state)
558 {
559 case SlotPowerState::on:
560 return "xyz.openbmc_project.State.Chassis.PowerState.On";
561 break;
562 case SlotPowerState::off:
563 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
564 break;
565 default:
566 return "";
567 break;
568 }
569};
570static void setSlotPowerState(const SlotPowerState state)
571{
572 slotPowerState = state;
573 chassisSlotIface->set_property("CurrentPowerState",
574 std::string(getSlotState(slotPowerState)));
575 chassisSlotIface->set_property("LastStateChangeTime", getCurrentTimeMs());
576}
577#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700578static void savePowerState(const PowerState state)
579{
580 powerStateSaveTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -0700581 std::chrono::milliseconds(TimerMap["PowerOffSaveMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700582 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
583 if (ec)
584 {
585 // operation_aborted is expected if timer is canceled before
586 // completion.
587 if (ec != boost::asio::error::operation_aborted)
588 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800589 lg2::error("Power-state save async_wait failed: {ERROR_MSG}",
590 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700591 }
592 return;
593 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300594 appState.set(PersistentState::Params::PowerState,
595 std::string{getChassisState(state)});
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700596 });
597}
598static void setPowerState(const PowerState state)
599{
600 powerState = state;
601 logStateTransition(state);
602
603 hostIface->set_property("CurrentHostState",
604 std::string(getHostState(powerState)));
605
606 chassisIface->set_property("CurrentPowerState",
607 std::string(getChassisState(powerState)));
608 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
609
610 // Save the power state for the restore policy
611 savePowerState(state);
612}
613
614enum class RestartCause
615{
616 command,
617 resetButton,
618 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700619 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700620 powerPolicyOn,
621 powerPolicyRestore,
622 softReset,
623};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700624static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700625static std::string getRestartCause(RestartCause cause)
626{
627 switch (cause)
628 {
629 case RestartCause::command:
630 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
631 break;
632 case RestartCause::resetButton:
633 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
634 break;
635 case RestartCause::powerButton:
636 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
637 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700638 case RestartCause::watchdog:
639 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
640 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700641 case RestartCause::powerPolicyOn:
Jason M. Bills418ce112021-09-08 15:15:05 -0700642 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyAlwaysOn";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700643 break;
644 case RestartCause::powerPolicyRestore:
Jason M. Bills418ce112021-09-08 15:15:05 -0700645 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyPreviousState";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700646 break;
647 case RestartCause::softReset:
648 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
649 break;
650 default:
651 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
652 break;
653 }
654}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700655static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700656{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700657 // Add this to the set of causes for this restart
658 causeSet.insert(cause);
659}
660static void clearRestartCause()
661{
662 // Clear the set for the next restart
663 causeSet.clear();
664}
665static void setRestartCauseProperty(const std::string& cause)
666{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800667 lg2::info("RestartCause set to {RESTART_CAUSE}", "RESTART_CAUSE", cause);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700668 restartCauseIface->set_property("RestartCause", cause);
669}
Rashmi RV89f61312020-01-22 15:41:50 +0530670
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300671#ifdef USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +0530672static void resetACBootProperty()
673{
674 if ((causeSet.contains(RestartCause::command)) ||
675 (causeSet.contains(RestartCause::softReset)))
676 {
677 conn->async_method_call(
678 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -0500679 if (ec)
680 {
681 lg2::error("failed to reset ACBoot property");
682 }
Rashmi RV89f61312020-01-22 15:41:50 +0530683 },
684 "xyz.openbmc_project.Settings",
685 "/xyz/openbmc_project/control/host0/ac_boot",
686 "org.freedesktop.DBus.Properties", "Set",
687 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
688 std::variant<std::string>{"False"});
689 }
690}
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300691#endif // USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +0530692
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700693static void setRestartCause()
694{
695 // Determine the actual restart cause based on the set of causes
696 std::string restartCause =
697 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
698 if (causeSet.contains(RestartCause::watchdog))
699 {
700 restartCause = getRestartCause(RestartCause::watchdog);
701 }
702 else if (causeSet.contains(RestartCause::command))
703 {
704 restartCause = getRestartCause(RestartCause::command);
705 }
706 else if (causeSet.contains(RestartCause::resetButton))
707 {
708 restartCause = getRestartCause(RestartCause::resetButton);
709 }
710 else if (causeSet.contains(RestartCause::powerButton))
711 {
712 restartCause = getRestartCause(RestartCause::powerButton);
713 }
714 else if (causeSet.contains(RestartCause::powerPolicyOn))
715 {
716 restartCause = getRestartCause(RestartCause::powerPolicyOn);
717 }
718 else if (causeSet.contains(RestartCause::powerPolicyRestore))
719 {
720 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
721 }
722 else if (causeSet.contains(RestartCause::softReset))
723 {
Matt Simmering58e379d2022-09-23 14:45:50 -0700724#if IGNORE_SOFT_RESETS_DURING_POST
725 if (ignoreNextSoftReset)
726 {
727 ignoreNextSoftReset = false;
728 return;
729 }
730#endif
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700731 restartCause = getRestartCause(RestartCause::softReset);
732 }
733
734 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700735}
736
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700737static void systemPowerGoodFailedLog()
738{
739 sd_journal_send(
740 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
741 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
742 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700743 TimerMap["SioPowerGoodWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700744}
745
746static void psPowerOKFailedLog()
747{
748 sd_journal_send(
749 "MESSAGE=PowerControl: power supply power good failed to assert",
750 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
751 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700752 TimerMap["PsPowerOKWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700753}
754
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700755static void powerRestorePolicyLog()
756{
757 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
758 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
759 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
760}
761
762static void powerButtonPressLog()
763{
764 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
765 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
766 "OpenBMC.0.1.PowerButtonPressed", NULL);
767}
768
769static void resetButtonPressLog()
770{
771 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
772 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
773 "OpenBMC.0.1.ResetButtonPressed", NULL);
774}
775
776static void nmiButtonPressLog()
777{
778 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
779 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
780 "OpenBMC.0.1.NMIButtonPressed", NULL);
781}
782
783static void nmiDiagIntLog()
784{
785 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
786 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
787 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
788}
789
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300790PersistentState::PersistentState()
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700791{
792 // create the power control directory if it doesn't exist
793 std::error_code ec;
794 if (!(std::filesystem::create_directories(powerControlDir, ec)))
795 {
796 if (ec.value() != 0)
797 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800798 lg2::error("failed to create {DIR_NAME}: {ERROR_MSG}", "DIR_NAME",
799 powerControlDir.string(), "ERROR_MSG", ec.message());
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300800 throw std::runtime_error("Failed to create state directory");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700801 }
802 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300803
804 // read saved state, it's ok, if the file doesn't exists
805 std::ifstream appStateStream(powerControlDir / stateFile);
806 if (!appStateStream.is_open())
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700807 {
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300808 lg2::info("Cannot open state file \'{PATH}\'", "PATH",
809 std::string(powerControlDir / stateFile));
810 stateData = nlohmann::json({});
811 return;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700812 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300813 try
814 {
815 appStateStream >> stateData;
816 if (stateData.is_discarded())
817 {
818 lg2::info("Cannot parse state file \'{PATH}\'", "PATH",
819 std::string(powerControlDir / stateFile));
820 stateData = nlohmann::json({});
821 return;
822 }
823 }
824 catch (const std::exception& ex)
825 {
826 lg2::info("Cannot read state file \'{PATH}\'", "PATH",
827 std::string(powerControlDir / stateFile));
828 stateData = nlohmann::json({});
829 return;
830 }
831}
832PersistentState::~PersistentState()
833{
834 saveState();
835}
836const std::string PersistentState::get(Params parameter)
837{
838 auto val = stateData.find(getName(parameter));
839 if (val != stateData.end())
840 {
841 return val->get<std::string>();
842 }
843 return getDefault(parameter);
844}
845void PersistentState::set(Params parameter, const std::string& value)
846{
847 stateData[getName(parameter)] = value;
848 saveState();
849}
850
851const std::string PersistentState::getName(const Params parameter)
852{
853 switch (parameter)
854 {
855 case Params::PowerState:
856 return "PowerState";
857 }
858 return "";
859}
860const std::string PersistentState::getDefault(const Params parameter)
861{
862 switch (parameter)
863 {
864 case Params::PowerState:
865 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
866 }
867 return "";
868}
869void PersistentState::saveState()
870{
871 std::ofstream appStateStream(powerControlDir / stateFile, std::ios::trunc);
872 if (!appStateStream.is_open())
873 {
874 lg2::error("Cannot write state file \'{PATH}\'", "PATH",
875 std::string(powerControlDir / stateFile));
876 return;
877 }
878 appStateStream << stateData.dump(indentationSize);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700879}
880
Patrick Williams48aa1f02023-05-10 07:50:30 -0500881static constexpr const char* setingsService = "xyz.openbmc_project.Settings";
882static constexpr const char* powerRestorePolicyIface =
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300883 "xyz.openbmc_project.Control.Power.RestorePolicy";
884#ifdef USE_ACBOOT
Patrick Williams48aa1f02023-05-10 07:50:30 -0500885static constexpr const char* powerACBootObject =
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300886 "/xyz/openbmc_project/control/host0/ac_boot";
Patrick Williams48aa1f02023-05-10 07:50:30 -0500887static constexpr const char* powerACBootIface =
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300888 "xyz.openbmc_project.Common.ACBoot";
889#endif // USE_ACBOOT
890
891namespace match_rules = sdbusplus::bus::match::rules;
892
893static int powerRestoreConfigHandler(sd_bus_message* m, void* context,
894 sd_bus_error*)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700895{
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300896 if (context == nullptr || m == nullptr)
897 {
898 throw std::runtime_error("Invalid match");
899 }
Patrick Williams439b9c32022-07-22 19:26:53 -0500900 sdbusplus::message_t message(m);
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300901 PowerRestoreController* powerRestore =
902 static_cast<PowerRestoreController*>(context);
903
904 if (std::string(message.get_member()) == "InterfacesAdded")
905 {
906 sdbusplus::message::object_path path;
907 boost::container::flat_map<std::string, dbusPropertiesList> data;
908
909 message.read(path, data);
910
911 for (auto& [iface, properties] : data)
912 {
913 if ((iface == powerRestorePolicyIface)
914#ifdef USE_ACBOOT
915 || (iface == powerACBootIface)
916#endif // USE_ACBOOT
917 )
918 {
919 powerRestore->setProperties(properties);
920 }
921 }
922 }
923 else if (std::string(message.get_member()) == "PropertiesChanged")
924 {
925 std::string interfaceName;
926 dbusPropertiesList propertiesChanged;
927
928 message.read(interfaceName, propertiesChanged);
929
930 powerRestore->setProperties(propertiesChanged);
931 }
932 return 1;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700933}
934
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300935void PowerRestoreController::run()
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700936{
Patrick Williams48aa1f02023-05-10 07:50:30 -0500937 std::string powerRestorePolicyObject = "/xyz/openbmc_project/control/host" +
938 node + "/power_restore_policy";
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300939 powerRestorePolicyLog();
940 // this list only needs to be created once
941 if (matches.empty())
942 {
943 matches.emplace_back(
944 *conn,
945 match_rules::interfacesAdded() +
946 match_rules::argNpath(0, powerRestorePolicyObject) +
947 match_rules::sender(setingsService),
948 powerRestoreConfigHandler, this);
949#ifdef USE_ACBOOT
950 matches.emplace_back(*conn,
951 match_rules::interfacesAdded() +
952 match_rules::argNpath(0, powerACBootObject) +
953 match_rules::sender(setingsService),
954 powerRestoreConfigHandler, this);
955 matches.emplace_back(*conn,
956 match_rules::propertiesChanged(powerACBootObject,
957 powerACBootIface) +
958 match_rules::sender(setingsService),
959 powerRestoreConfigHandler, this);
960#endif // USE_ACBOOT
961 }
962
963 // Check if it's already on DBus
964 conn->async_method_call(
965 [this](boost::system::error_code ec,
966 const dbusPropertiesList properties) {
Patrick Williams48aa1f02023-05-10 07:50:30 -0500967 if (ec)
968 {
969 return;
970 }
971 setProperties(properties);
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300972 },
973 setingsService, powerRestorePolicyObject,
974 "org.freedesktop.DBus.Properties", "GetAll", powerRestorePolicyIface);
975
976#ifdef USE_ACBOOT
977 // Check if it's already on DBus
978 conn->async_method_call(
979 [this](boost::system::error_code ec,
980 const dbusPropertiesList properties) {
Patrick Williams48aa1f02023-05-10 07:50:30 -0500981 if (ec)
982 {
983 return;
984 }
985 setProperties(properties);
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300986 },
987 setingsService, powerACBootObject, "org.freedesktop.DBus.Properties",
988 "GetAll", powerACBootIface);
989#endif
990}
991
992void PowerRestoreController::setProperties(const dbusPropertiesList& props)
993{
994 for (auto& [property, propValue] : props)
995 {
996 if (property == "PowerRestorePolicy")
997 {
998 const std::string* value = std::get_if<std::string>(&propValue);
999 if (value == nullptr)
1000 {
1001 lg2::error("Unable to read Power Restore Policy");
1002 continue;
1003 }
1004 powerRestorePolicy = *value;
1005 }
1006 else if (property == "PowerRestoreDelay")
1007 {
1008 const uint64_t* value = std::get_if<uint64_t>(&propValue);
1009 if (value == nullptr)
1010 {
1011 lg2::error("Unable to read Power Restore Delay");
1012 continue;
1013 }
1014 powerRestoreDelay = *value / 1000000; // usec to sec
1015 }
1016#ifdef USE_ACBOOT
1017 else if (property == "ACBoot")
1018 {
1019 const std::string* value = std::get_if<std::string>(&propValue);
1020 if (value == nullptr)
1021 {
1022 lg2::error("Unable to read AC Boot status");
1023 continue;
1024 }
1025 acBoot = *value;
1026 }
1027#endif // USE_ACBOOT
1028 }
1029 invokeIfReady();
1030}
1031
1032void PowerRestoreController::invokeIfReady()
1033{
1034 if ((powerRestorePolicy.empty()) || (powerRestoreDelay < 0))
1035 {
1036 return;
1037 }
1038#ifdef USE_ACBOOT
1039 if (acBoot.empty() || acBoot == "Unknown")
1040 {
1041 return;
1042 }
1043#endif
1044
1045 matches.clear();
1046 if (!timerFired)
1047 {
1048 // Calculate the delay from now to meet the requested delay
1049 // Subtract the approximate uboot time
1050 static constexpr const int ubootSeconds = 20;
1051 int delay = powerRestoreDelay - ubootSeconds;
1052 // Subtract the time since boot
1053 struct sysinfo info = {};
1054 if (sysinfo(&info) == 0)
1055 {
1056 delay -= info.uptime;
1057 }
1058
1059 if (delay > 0)
1060 {
1061 powerRestoreTimer.expires_after(std::chrono::seconds(delay));
1062 lg2::info("Power Restore delay of {DELAY} seconds started", "DELAY",
1063 delay);
Patrick Williams48aa1f02023-05-10 07:50:30 -05001064 powerRestoreTimer.async_wait(
1065 [this](const boost::system::error_code ec) {
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001066 if (ec)
1067 {
1068 // operation_aborted is expected if timer is canceled before
1069 // completion.
1070 if (ec == boost::asio::error::operation_aborted)
1071 {
1072 return;
1073 }
1074 lg2::error(
1075 "power restore policy async_wait failed: {ERROR_MSG}",
1076 "ERROR_MSG", ec.message());
1077 }
1078 else
1079 {
1080 lg2::info("Power Restore delay timer expired");
1081 }
1082 invoke();
1083 });
1084 timerFired = true;
1085 }
1086 else
1087 {
1088 invoke();
1089 }
1090 }
1091}
1092
1093void PowerRestoreController::invoke()
1094{
1095 // we want to run Power Restore only once
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001096 if (policyInvoked)
1097 {
1098 return;
1099 }
1100 policyInvoked = true;
1101
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001102 lg2::info("Invoking Power Restore Policy {POLICY}", "POLICY",
1103 powerRestorePolicy);
1104 if (powerRestorePolicy ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001105 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
1106 {
1107 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001108 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001109 }
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001110 else if (powerRestorePolicy ==
Jason M. Bills418ce112021-09-08 15:15:05 -07001111 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore")
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001112 {
1113 if (wasPowerDropped())
1114 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001115 lg2::info("Power was dropped, restoring Host On state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001116 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001117 setRestartCauseProperty(
1118 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001119 }
1120 else
1121 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001122 lg2::info("No power drop, restoring Host Off state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001123 }
1124 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -07001125 // We're done with the previous power state for the restore policy, so store
1126 // the current state
1127 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001128}
1129
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001130bool PowerRestoreController::wasPowerDropped()
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001131{
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001132 std::string state = appState.get(PersistentState::Params::PowerState);
1133 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001134}
1135
Zev Weiss676ef2c2021-09-02 21:54:02 -05001136static void waitForGPIOEvent(const std::string& name,
1137 const std::function<void(bool)>& eventHandler,
1138 gpiod::line& line,
1139 boost::asio::posix::stream_descriptor& event)
1140{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001141 event.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1142 [&name, eventHandler, &line,
1143 &event](const boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001144 if (ec)
1145 {
1146 lg2::error("{GPIO_NAME} fd handler error: {ERROR_MSG}", "GPIO_NAME",
1147 name, "ERROR_MSG", ec.message());
1148 // TODO: throw here to force power-control to
1149 // restart?
1150 return;
1151 }
1152 gpiod::line_event line_event = line.event_read();
1153 eventHandler(line_event.event_type == gpiod::line_event::RISING_EDGE);
1154 waitForGPIOEvent(name, eventHandler, line, event);
1155 });
Zev Weiss676ef2c2021-09-02 21:54:02 -05001156}
1157
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001158static bool requestGPIOEvents(
Zev Weiss676ef2c2021-09-02 21:54:02 -05001159 const std::string& name, const std::function<void(bool)>& handler,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001160 gpiod::line& gpioLine,
1161 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
1162{
1163 // Find the GPIO line
1164 gpioLine = gpiod::find_line(name);
1165 if (!gpioLine)
1166 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001167 lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001168 return false;
1169 }
1170
1171 try
1172 {
Andrei Kartashev3efcf372021-12-29 15:32:17 +03001173 gpioLine.request({appName, gpiod::line_request::EVENT_BOTH_EDGES, {}});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001174 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001175 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001176 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001177 lg2::error("Failed to request events for {GPIO_NAME}: {ERROR}",
1178 "GPIO_NAME", name, "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001179 return false;
1180 }
1181
1182 int gpioLineFd = gpioLine.event_get_fd();
1183 if (gpioLineFd < 0)
1184 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001185 lg2::error("Failed to get {GPIO_NAME} fd", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001186 return false;
1187 }
1188
1189 gpioEventDescriptor.assign(gpioLineFd);
1190
Zev Weiss676ef2c2021-09-02 21:54:02 -05001191 waitForGPIOEvent(name, handler, gpioLine, gpioEventDescriptor);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001192 return true;
1193}
1194
1195static bool setGPIOOutput(const std::string& name, const int value,
1196 gpiod::line& gpioLine)
1197{
1198 // Find the GPIO line
1199 gpioLine = gpiod::find_line(name);
1200 if (!gpioLine)
1201 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001202 lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001203 return false;
1204 }
1205
1206 // Request GPIO output to specified value
1207 try
1208 {
Andrei Kartashev3efcf372021-12-29 15:32:17 +03001209 gpioLine.request({appName, gpiod::line_request::DIRECTION_OUTPUT, {}},
1210 value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001211 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001212 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001213 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001214 lg2::error("Failed to request {GPIO_NAME} output: {ERROR}", "GPIO_NAME",
1215 name, "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001216 return false;
1217 }
1218
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001219 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1220 "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001221 return true;
1222}
1223
1224static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1225 const std::string& name, const int value,
1226 const int durationMs)
1227{
1228 // Set the masked GPIO line to the specified value
1229 maskedGPIOLine.set_value(value);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001230 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1231 "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001232 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001233 gpioAssertTimer.async_wait(
1234 [maskedGPIOLine, value, name](const boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001235 // Set the masked GPIO line back to the opposite value
1236 maskedGPIOLine.set_value(!value);
1237 lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
1238 if (ec)
1239 {
1240 // operation_aborted is expected if timer is canceled before
1241 // completion.
1242 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001243 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001244 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1245 "GPIO_NAME", name, "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001246 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05001247 }
1248 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001249 return 0;
1250}
1251
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001252static int setGPIOOutputForMs(const ConfigData& config, const int value,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001253 const int durationMs)
1254{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001255 // If the requested GPIO is masked, use the mask line to set the output
1256 if (powerButtonMask && config.lineName == powerOutConfig.lineName)
1257 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001258 return setMaskedGPIOOutputForMs(powerButtonMask, config.lineName, value,
1259 durationMs);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001260 }
1261 if (resetButtonMask && config.lineName == resetOutConfig.lineName)
1262 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001263 return setMaskedGPIOOutputForMs(resetButtonMask, config.lineName, value,
1264 durationMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001265 }
1266
1267 // No mask set, so request and set the GPIO normally
1268 gpiod::line gpioLine;
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001269 if (!setGPIOOutput(config.lineName, value, gpioLine))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001270 {
1271 return -1;
1272 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001273 const std::string name = config.lineName;
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001274
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001275 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001276 gpioAssertTimer.async_wait(
1277 [gpioLine, value, name](const boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001278 // Set the GPIO line back to the opposite value
1279 gpioLine.set_value(!value);
1280 lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
1281 if (ec)
1282 {
1283 // operation_aborted is expected if timer is canceled before
1284 // completion.
1285 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001286 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001287 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1288 "GPIO_NAME", name, "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001289 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05001290 }
1291 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001292 return 0;
1293}
1294
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001295static int assertGPIOForMs(const ConfigData& config, const int durationMs)
1296{
1297 return setGPIOOutputForMs(config, config.polarity, durationMs);
1298}
1299
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001300static void powerOn()
1301{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001302 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001303}
Naveen Moses117c34e2021-05-26 20:10:51 +05301304#ifdef CHASSIS_SYSTEM_RESET
1305static int slotPowerOn()
1306{
1307 if (power_control::slotPowerState != power_control::SlotPowerState::on)
1308 {
Naveen Moses117c34e2021-05-26 20:10:51 +05301309 slotPowerLine.set_value(1);
1310
1311 if (slotPowerLine.get_value() > 0)
1312 {
1313 setSlotPowerState(SlotPowerState::on);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001314 lg2::info("Slot Power is switched On\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301315 }
1316 else
1317 {
1318 return -1;
1319 }
1320 }
1321 else
1322 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001323 lg2::info("Slot Power is already in 'On' state\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301324 return -1;
1325 }
1326 return 0;
1327}
1328static int slotPowerOff()
1329{
1330 if (power_control::slotPowerState != power_control::SlotPowerState::off)
1331 {
1332 slotPowerLine.set_value(0);
1333
1334 if (!(slotPowerLine.get_value() > 0))
1335 {
1336 setSlotPowerState(SlotPowerState::off);
1337 setPowerState(PowerState::off);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001338 lg2::info("Slot Power is switched Off\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301339 }
1340 else
1341 {
1342 return -1;
1343 }
1344 }
1345 else
1346 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001347 lg2::info("Slot Power is already in 'Off' state\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301348 return -1;
1349 }
1350 return 0;
1351}
1352static void slotPowerCycle()
1353{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001354 lg2::info("Slot Power Cycle started\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301355 slotPowerOff();
1356 slotPowerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001357 std::chrono::milliseconds(TimerMap["SlotPowerCycleMs"]));
Naveen Moses117c34e2021-05-26 20:10:51 +05301358 slotPowerCycleTimer.async_wait([](const boost::system::error_code ec) {
1359 if (ec)
1360 {
1361 if (ec != boost::asio::error::operation_aborted)
1362 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001363 lg2::error(
1364 "Slot Power cycle timer async_wait failed: {ERROR_MSG}",
1365 "ERROR_MSG", ec.message());
Naveen Moses117c34e2021-05-26 20:10:51 +05301366 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001367 lg2::info("Slot Power cycle timer canceled\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301368 return;
1369 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001370 lg2::info("Slot Power cycle timer completed\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301371 slotPowerOn();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001372 lg2::info("Slot Power Cycle Completed\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301373 });
1374}
1375#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001376static void gracefulPowerOff()
1377{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001378 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001379}
1380
1381static void forcePowerOff()
1382{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001383 if (assertGPIOForMs(powerOutConfig, TimerMap["ForceOffPulseMs"]) < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001384 {
1385 return;
1386 }
1387
Jason M. Billsc6961b62021-10-21 14:08:02 -07001388 // If the force off timer expires, then the power-button override failed
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001389 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1390 if (ec)
1391 {
1392 // operation_aborted is expected if timer is canceled before
1393 // completion.
1394 if (ec != boost::asio::error::operation_aborted)
1395 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001396 lg2::error("Force power off async_wait failed: {ERROR_MSG}",
1397 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001398 }
1399 return;
1400 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001401
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001402 lg2::error("Power-button override failed. Not sure what to do now.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001403 });
1404}
1405
1406static void reset()
1407{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001408 assertGPIOForMs(resetOutConfig, TimerMap["ResetPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001409}
1410
1411static void gracefulPowerOffTimerStart()
1412{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001413 lg2::info("Graceful power-off timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001414 gracefulPowerOffTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001415 std::chrono::seconds(TimerMap["GracefulPowerOffS"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001416 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1417 if (ec)
1418 {
1419 // operation_aborted is expected if timer is canceled before
1420 // completion.
1421 if (ec != boost::asio::error::operation_aborted)
1422 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001423 lg2::error("Graceful power-off async_wait failed: {ERROR_MSG}",
1424 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001425 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001426 lg2::info("Graceful power-off timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001427 return;
1428 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001429 lg2::info("Graceful power-off timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001430 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1431 });
1432}
1433
1434static void powerCycleTimerStart()
1435{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001436 lg2::info("Power-cycle timer started");
Priyatharshan P70120512020-09-16 18:47:20 +05301437 powerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001438 std::chrono::milliseconds(TimerMap["PowerCycleMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001439 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1440 if (ec)
1441 {
1442 // operation_aborted is expected if timer is canceled before
1443 // completion.
1444 if (ec != boost::asio::error::operation_aborted)
1445 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001446 lg2::error("Power-cycle async_wait failed: {ERROR_MSG}",
1447 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001448 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001449 lg2::info("Power-cycle timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001450 return;
1451 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001452 lg2::info("Power-cycle timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001453 sendPowerControlEvent(Event::powerCycleTimerExpired);
1454 });
1455}
1456
1457static void psPowerOKWatchdogTimerStart()
1458{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001459 lg2::info("power supply power OK watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001460 psPowerOKWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001461 std::chrono::milliseconds(TimerMap["PsPowerOKWatchdogMs"]));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001462 psPowerOKWatchdogTimer.async_wait([](const boost::system::error_code ec) {
1463 if (ec)
1464 {
1465 // operation_aborted is expected if timer is canceled before
1466 // completion.
1467 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001468 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001469 lg2::error(
1470 "power supply power OK watchdog async_wait failed: {ERROR_MSG}",
1471 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001472 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001473 lg2::info("power supply power OK watchdog timer canceled");
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001474 return;
1475 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001476 lg2::info("power supply power OK watchdog timer expired");
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001477 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1478 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001479}
1480
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001481static void warmResetCheckTimerStart()
1482{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001483 lg2::info("Warm reset check timer started");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001484 warmResetCheckTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001485 std::chrono::milliseconds(TimerMap["WarmResetCheckMs"]));
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001486 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1487 if (ec)
1488 {
1489 // operation_aborted is expected if timer is canceled before
1490 // completion.
1491 if (ec != boost::asio::error::operation_aborted)
1492 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001493 lg2::error("Warm reset check async_wait failed: {ERROR_MSG}",
1494 "ERROR_MSG", ec.message());
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001495 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001496 lg2::info("Warm reset check timer canceled");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001497 return;
1498 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001499 lg2::info("Warm reset check timer completed");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001500 sendPowerControlEvent(Event::warmResetDetected);
1501 });
1502}
1503
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001504static void pohCounterTimerStart()
1505{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001506 lg2::info("POH timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001507 // Set the time-out as 1 hour, to align with POH command in ipmid
1508 pohCounterTimer.expires_after(std::chrono::hours(1));
1509 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1510 if (ec)
1511 {
1512 // operation_aborted is expected if timer is canceled before
1513 // completion.
1514 if (ec != boost::asio::error::operation_aborted)
1515 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001516 lg2::error("POH timer async_wait failed: {ERROR_MSG}",
1517 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001518 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001519 lg2::info("POH timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001520 return;
1521 }
1522
1523 if (getHostState(powerState) !=
1524 "xyz.openbmc_project.State.Host.HostState.Running")
1525 {
1526 return;
1527 }
1528
1529 conn->async_method_call(
1530 [](boost::system::error_code ec,
1531 const std::variant<uint32_t>& pohCounterProperty) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001532 if (ec)
1533 {
1534 lg2::error("error getting poh counter");
1535 return;
1536 }
1537 const uint32_t* pohCounter =
1538 std::get_if<uint32_t>(&pohCounterProperty);
1539 if (pohCounter == nullptr)
1540 {
1541 lg2::error("unable to read poh counter");
1542 return;
1543 }
1544
1545 conn->async_method_call(
1546 [](boost::system::error_code ec) {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001547 if (ec)
1548 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001549 lg2::error("failed to set poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001550 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05001551 },
1552 "xyz.openbmc_project.Settings",
1553 "/xyz/openbmc_project/state/chassis0",
1554 "org.freedesktop.DBus.Properties", "Set",
1555 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1556 std::variant<uint32_t>(*pohCounter + 1));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001557 },
1558 "xyz.openbmc_project.Settings",
1559 "/xyz/openbmc_project/state/chassis0",
1560 "org.freedesktop.DBus.Properties", "Get",
1561 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1562
1563 pohCounterTimerStart();
1564 });
1565}
1566
1567static void currentHostStateMonitor()
1568{
Yong Li8d660212019-12-27 10:18:10 +08001569 if (getHostState(powerState) ==
1570 "xyz.openbmc_project.State.Host.HostState.Running")
1571 {
1572 pohCounterTimerStart();
1573 // Clear the restart cause set for the next restart
1574 clearRestartCause();
1575 }
1576 else
1577 {
1578 pohCounterTimer.cancel();
1579 // Set the restart cause set for this restart
1580 setRestartCause();
1581 }
1582
Patrick Williams48aa1f02023-05-10 07:50:30 -05001583 static auto match =
1584 sdbusplus::bus::match_t(*conn,
1585 "type='signal',member='PropertiesChanged', "
1586 "interface='org.freedesktop.DBus.Properties', "
1587 "arg0='xyz.openbmc_project.State.Host'",
1588 [](sdbusplus::message_t& message) {
1589 std::string intfName;
1590 std::map<std::string, std::variant<std::string>> properties;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001591
Patrick Williams48aa1f02023-05-10 07:50:30 -05001592 try
1593 {
1594 message.read(intfName, properties);
1595 }
1596 catch (const std::exception& e)
1597 {
1598 lg2::error("Unable to read host state: {ERROR}", "ERROR", e);
1599 return;
1600 }
1601 if (properties.empty())
1602 {
1603 lg2::error("ERROR: Empty PropertiesChanged signal received");
1604 return;
1605 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001606
Patrick Williams48aa1f02023-05-10 07:50:30 -05001607 // We only want to check for CurrentHostState
1608 if (properties.begin()->first != "CurrentHostState")
1609 {
1610 return;
1611 }
1612 std::string* currentHostState =
1613 std::get_if<std::string>(&(properties.begin()->second));
1614 if (currentHostState == nullptr)
1615 {
1616 lg2::error("{PROPERTY} property invalid", "PROPERTY",
1617 properties.begin()->first);
1618 return;
1619 }
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001620
Patrick Williams48aa1f02023-05-10 07:50:30 -05001621 if (*currentHostState ==
1622 "xyz.openbmc_project.State.Host.HostState.Running")
1623 {
1624 pohCounterTimerStart();
1625 // Clear the restart cause set for the next restart
1626 clearRestartCause();
1627 sd_journal_send("MESSAGE=Host system DC power is on", "PRIORITY=%i",
1628 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
1629 "OpenBMC.0.1.DCPowerOn", NULL);
1630 }
1631 else
1632 {
1633 pohCounterTimer.cancel();
1634 // POST_COMPLETE GPIO event is not working in some platforms
1635 // when power state is changed to OFF. This resulted in
1636 // 'OperatingSystemState' to stay at 'Standby', even though
1637 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1638 // if HostState is trurned to OFF.
1639 setOperatingSystemState(OperatingSystemStateStage::Inactive);
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301640
Patrick Williams48aa1f02023-05-10 07:50:30 -05001641 // Set the restart cause set for this restart
1642 setRestartCause();
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001643#ifdef USE_ACBOOT
Patrick Williams48aa1f02023-05-10 07:50:30 -05001644 resetACBootProperty();
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001645#endif // USE_ACBOOT
Patrick Williams48aa1f02023-05-10 07:50:30 -05001646 sd_journal_send("MESSAGE=Host system DC power is off",
1647 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
1648 "OpenBMC.0.1.DCPowerOff", NULL);
1649 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001650 });
1651}
1652
1653static void sioPowerGoodWatchdogTimerStart()
1654{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001655 lg2::info("SIO power good watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001656 sioPowerGoodWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001657 std::chrono::milliseconds(TimerMap["SioPowerGoodWatchdogMs"]));
Patrick Williams48aa1f02023-05-10 07:50:30 -05001658 sioPowerGoodWatchdogTimer.async_wait(
1659 [](const boost::system::error_code ec) {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001660 if (ec)
1661 {
1662 // operation_aborted is expected if timer is canceled before
1663 // completion.
1664 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001665 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001666 lg2::error(
1667 "SIO power good watchdog async_wait failed: {ERROR_MSG}",
1668 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001669 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001670 lg2::info("SIO power good watchdog timer canceled");
1671 return;
1672 }
1673 lg2::info("SIO power good watchdog timer completed");
1674 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1675 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001676}
1677
1678static void powerStateOn(const Event event)
1679{
1680 logEvent(__FUNCTION__, event);
1681 switch (event)
1682 {
1683 case Event::psPowerOKDeAssert:
1684 setPowerState(PowerState::off);
1685 // DC power is unexpectedly lost, beep
1686 beep(beepPowerFail);
1687 break;
1688 case Event::sioS5Assert:
1689 setPowerState(PowerState::transitionToOff);
Matt Simmering58e379d2022-09-23 14:45:50 -07001690#if IGNORE_SOFT_RESETS_DURING_POST
1691 // Only recognize soft resets once host gets past POST COMPLETE
1692 if (operatingSystemState != OperatingSystemStateStage::Standby)
1693 {
1694 ignoreNextSoftReset = true;
1695 }
1696#endif
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001697 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001698 break;
Jason M. Billsfb957332021-01-28 13:18:46 -08001699#if USE_PLT_RST
1700 case Event::pltRstAssert:
1701#else
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001702 case Event::postCompleteDeAssert:
Jason M. Billsfb957332021-01-28 13:18:46 -08001703#endif
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001704 setPowerState(PowerState::checkForWarmReset);
Matt Simmering58e379d2022-09-23 14:45:50 -07001705#if IGNORE_SOFT_RESETS_DURING_POST
1706 // Only recognize soft resets once host gets past POST COMPLETE
1707 if (operatingSystemState != OperatingSystemStateStage::Standby)
1708 {
1709 ignoreNextSoftReset = true;
1710 }
1711#endif
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001712 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001713 warmResetCheckTimerStart();
1714 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001715 case Event::powerButtonPressed:
1716 setPowerState(PowerState::gracefulTransitionToOff);
1717 gracefulPowerOffTimerStart();
1718 break;
1719 case Event::powerOffRequest:
1720 setPowerState(PowerState::transitionToOff);
1721 forcePowerOff();
1722 break;
1723 case Event::gracefulPowerOffRequest:
1724 setPowerState(PowerState::gracefulTransitionToOff);
1725 gracefulPowerOffTimerStart();
1726 gracefulPowerOff();
1727 break;
1728 case Event::powerCycleRequest:
1729 setPowerState(PowerState::transitionToCycleOff);
1730 forcePowerOff();
1731 break;
1732 case Event::gracefulPowerCycleRequest:
1733 setPowerState(PowerState::gracefulTransitionToCycleOff);
1734 gracefulPowerOffTimerStart();
1735 gracefulPowerOff();
1736 break;
1737 case Event::resetRequest:
1738 reset();
1739 break;
1740 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001741 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001742 break;
1743 }
1744}
1745
1746static void powerStateWaitForPSPowerOK(const Event event)
1747{
1748 logEvent(__FUNCTION__, event);
1749 switch (event)
1750 {
1751 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301752 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001753 // Cancel any GPIO assertions held during the transition
1754 gpioAssertTimer.cancel();
1755 psPowerOKWatchdogTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301756 if (sioEnabled == true)
1757 {
1758 sioPowerGoodWatchdogTimerStart();
1759 setPowerState(PowerState::waitForSIOPowerGood);
1760 }
1761 else
1762 {
1763 setPowerState(PowerState::on);
1764 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001765 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301766 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001767 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001768 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001769 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001770 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001771 case Event::sioPowerGoodAssert:
1772 psPowerOKWatchdogTimer.cancel();
1773 setPowerState(PowerState::on);
1774 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001775 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001776 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001777 break;
1778 }
1779}
1780
1781static void powerStateWaitForSIOPowerGood(const Event event)
1782{
1783 logEvent(__FUNCTION__, event);
1784 switch (event)
1785 {
1786 case Event::sioPowerGoodAssert:
1787 sioPowerGoodWatchdogTimer.cancel();
1788 setPowerState(PowerState::on);
1789 break;
1790 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001791 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001792 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001793 break;
1794 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001795 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001796 break;
1797 }
1798}
1799
1800static void powerStateOff(const Event event)
1801{
1802 logEvent(__FUNCTION__, event);
1803 switch (event)
1804 {
1805 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301806 {
1807 if (sioEnabled == true)
1808 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001809 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301810 setPowerState(PowerState::waitForSIOPowerGood);
1811 }
1812 else
1813 {
1814 setPowerState(PowerState::on);
1815 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001816 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301817 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001818 case Event::sioS5DeAssert:
Jason M. Billsfe159032022-09-01 16:03:37 -07001819 psPowerOKWatchdogTimerStart();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001820 setPowerState(PowerState::waitForPSPowerOK);
1821 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001822 case Event::sioPowerGoodAssert:
1823 setPowerState(PowerState::on);
1824 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001825 case Event::powerButtonPressed:
1826 psPowerOKWatchdogTimerStart();
1827 setPowerState(PowerState::waitForPSPowerOK);
1828 break;
1829 case Event::powerOnRequest:
1830 psPowerOKWatchdogTimerStart();
1831 setPowerState(PowerState::waitForPSPowerOK);
1832 powerOn();
1833 break;
1834 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001835 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001836 break;
1837 }
1838}
1839
1840static void powerStateTransitionToOff(const Event event)
1841{
1842 logEvent(__FUNCTION__, event);
1843 switch (event)
1844 {
1845 case Event::psPowerOKDeAssert:
1846 // Cancel any GPIO assertions held during the transition
1847 gpioAssertTimer.cancel();
1848 setPowerState(PowerState::off);
1849 break;
1850 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001851 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001852 break;
1853 }
1854}
1855
1856static void powerStateGracefulTransitionToOff(const Event event)
1857{
1858 logEvent(__FUNCTION__, event);
1859 switch (event)
1860 {
1861 case Event::psPowerOKDeAssert:
1862 gracefulPowerOffTimer.cancel();
1863 setPowerState(PowerState::off);
1864 break;
1865 case Event::gracefulPowerOffTimerExpired:
1866 setPowerState(PowerState::on);
1867 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001868 case Event::powerOffRequest:
1869 gracefulPowerOffTimer.cancel();
1870 setPowerState(PowerState::transitionToOff);
1871 forcePowerOff();
1872 break;
1873 case Event::powerCycleRequest:
1874 gracefulPowerOffTimer.cancel();
1875 setPowerState(PowerState::transitionToCycleOff);
1876 forcePowerOff();
1877 break;
1878 case Event::resetRequest:
1879 gracefulPowerOffTimer.cancel();
1880 setPowerState(PowerState::on);
1881 reset();
1882 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001883 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001884 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001885 break;
1886 }
1887}
1888
1889static void powerStateCycleOff(const Event event)
1890{
1891 logEvent(__FUNCTION__, event);
1892 switch (event)
1893 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001894 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301895 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001896 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301897 if (sioEnabled == true)
1898 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001899 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301900 setPowerState(PowerState::waitForSIOPowerGood);
1901 }
1902 else
1903 {
1904 setPowerState(PowerState::on);
1905 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001906 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301907 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001908 case Event::sioS5DeAssert:
1909 powerCycleTimer.cancel();
Jason M. Billsfe159032022-09-01 16:03:37 -07001910 psPowerOKWatchdogTimerStart();
Jason M. Bills35aa6652020-04-30 16:24:55 -07001911 setPowerState(PowerState::waitForPSPowerOK);
1912 break;
1913 case Event::powerButtonPressed:
1914 powerCycleTimer.cancel();
1915 psPowerOKWatchdogTimerStart();
1916 setPowerState(PowerState::waitForPSPowerOK);
1917 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001918 case Event::powerCycleTimerExpired:
1919 psPowerOKWatchdogTimerStart();
1920 setPowerState(PowerState::waitForPSPowerOK);
1921 powerOn();
1922 break;
1923 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001924 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001925 break;
1926 }
1927}
1928
1929static void powerStateTransitionToCycleOff(const Event event)
1930{
1931 logEvent(__FUNCTION__, event);
1932 switch (event)
1933 {
1934 case Event::psPowerOKDeAssert:
1935 // Cancel any GPIO assertions held during the transition
1936 gpioAssertTimer.cancel();
1937 setPowerState(PowerState::cycleOff);
1938 powerCycleTimerStart();
1939 break;
1940 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001941 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001942 break;
1943 }
1944}
1945
1946static void powerStateGracefulTransitionToCycleOff(const Event event)
1947{
1948 logEvent(__FUNCTION__, event);
1949 switch (event)
1950 {
1951 case Event::psPowerOKDeAssert:
1952 gracefulPowerOffTimer.cancel();
1953 setPowerState(PowerState::cycleOff);
1954 powerCycleTimerStart();
1955 break;
1956 case Event::gracefulPowerOffTimerExpired:
1957 setPowerState(PowerState::on);
1958 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001959 case Event::powerOffRequest:
1960 gracefulPowerOffTimer.cancel();
1961 setPowerState(PowerState::transitionToOff);
1962 forcePowerOff();
1963 break;
1964 case Event::powerCycleRequest:
1965 gracefulPowerOffTimer.cancel();
1966 setPowerState(PowerState::transitionToCycleOff);
1967 forcePowerOff();
1968 break;
1969 case Event::resetRequest:
1970 gracefulPowerOffTimer.cancel();
1971 setPowerState(PowerState::on);
1972 reset();
1973 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001974 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001975 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001976 break;
1977 }
1978}
1979
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001980static void powerStateCheckForWarmReset(const Event event)
1981{
1982 logEvent(__FUNCTION__, event);
1983 switch (event)
1984 {
1985 case Event::sioS5Assert:
1986 warmResetCheckTimer.cancel();
1987 setPowerState(PowerState::transitionToOff);
1988 break;
1989 case Event::warmResetDetected:
1990 setPowerState(PowerState::on);
1991 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001992 case Event::psPowerOKDeAssert:
1993 warmResetCheckTimer.cancel();
1994 setPowerState(PowerState::off);
1995 // DC power is unexpectedly lost, beep
1996 beep(beepPowerFail);
1997 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001998 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001999 lg2::info("No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002000 break;
2001 }
2002}
2003
Zev Weiss584aa132021-09-02 19:21:52 -05002004static void psPowerOKHandler(bool state)
2005{
Patrick Williams48aa1f02023-05-10 07:50:30 -05002006 Event powerControlEvent = state ? Event::psPowerOKAssert
2007 : Event::psPowerOKDeAssert;
Zev Weiss584aa132021-09-02 19:21:52 -05002008 sendPowerControlEvent(powerControlEvent);
2009}
2010
Zev Weiss584aa132021-09-02 19:21:52 -05002011static void sioPowerGoodHandler(bool state)
2012{
Patrick Williams48aa1f02023-05-10 07:50:30 -05002013 Event powerControlEvent = state ? Event::sioPowerGoodAssert
2014 : Event::sioPowerGoodDeAssert;
Zev Weiss584aa132021-09-02 19:21:52 -05002015 sendPowerControlEvent(powerControlEvent);
2016}
2017
Zev Weiss584aa132021-09-02 19:21:52 -05002018static void sioOnControlHandler(bool state)
2019{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002020 lg2::info("SIO_ONCONTROL value changed: {VALUE}", "VALUE",
2021 static_cast<int>(state));
Zev Weiss584aa132021-09-02 19:21:52 -05002022}
2023
Zev Weiss584aa132021-09-02 19:21:52 -05002024static void sioS5Handler(bool state)
2025{
2026 Event powerControlEvent = state ? Event::sioS5DeAssert : Event::sioS5Assert;
2027 sendPowerControlEvent(powerControlEvent);
2028}
2029
Zev Weiss584aa132021-09-02 19:21:52 -05002030static void powerButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002031{
Zev Weiss584aa132021-09-02 19:21:52 -05002032 powerButtonIface->set_property("ButtonPressed", !state);
2033 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002034 {
2035 powerButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002036 if (!powerButtonMask)
2037 {
2038 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002039 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002040 }
2041 else
2042 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002043 lg2::info("power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002044 }
2045 }
Zev Weiss584aa132021-09-02 19:21:52 -05002046}
2047
Zev Weiss584aa132021-09-02 19:21:52 -05002048static void resetButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002049{
Zev Weiss584aa132021-09-02 19:21:52 -05002050 resetButtonIface->set_property("ButtonPressed", !state);
2051 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002052 {
2053 resetButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002054 if (!resetButtonMask)
2055 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002056 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002057 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002058 }
2059 else
2060 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002061 lg2::info("reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002062 }
2063 }
Zev Weiss584aa132021-09-02 19:21:52 -05002064}
2065
Vijay Khemka04175c22020-10-09 14:28:11 -07002066#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002067static constexpr auto systemdBusname = "org.freedesktop.systemd1";
2068static constexpr auto systemdPath = "/org/freedesktop/systemd1";
2069static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
2070static constexpr auto systemTargetName = "chassis-system-reset.target";
2071
2072void systemReset()
2073{
2074 conn->async_method_call(
2075 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002076 if (ec)
2077 {
2078 lg2::error("Failed to call chassis system reset: {ERR}", "ERR",
2079 ec.message());
2080 }
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002081 },
2082 systemdBusname, systemdPath, systemdInterface, "StartUnit",
2083 systemTargetName, "replace");
2084}
Vijay Khemka04175c22020-10-09 14:28:11 -07002085#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002086
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002087static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002088{
2089 conn->async_method_call(
2090 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002091 if (ec)
2092 {
2093 lg2::error("failed to set NMI source");
2094 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002095 },
Chen Yugang303bd582019-11-01 08:45:06 +08002096 "xyz.openbmc_project.Settings",
2097 "/xyz/openbmc_project/Chassis/Control/NMISource",
2098 "org.freedesktop.DBus.Properties", "Set",
2099 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
2100 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002101}
2102
2103static void nmiReset(void)
2104{
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002105 const static constexpr int nmiOutPulseTimeMs = 200;
2106
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002107 lg2::info("NMI out action");
Jian Zhang461a1662022-09-22 11:29:01 +08002108 nmiOutLine.set_value(nmiOutConfig.polarity);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002109 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME",
Jian Zhang461a1662022-09-22 11:29:01 +08002110 nmiOutConfig.lineName, "GPIO_VALUE", nmiOutConfig.polarity);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002111 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2112 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2113 // restore the NMI_OUT GPIO line back to the opposite value
Jian Zhang461a1662022-09-22 11:29:01 +08002114 nmiOutLine.set_value(!nmiOutConfig.polarity);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002115 lg2::info("{GPIO_NAME} released", "GPIO_NAME", nmiOutConfig.lineName);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002116 if (ec)
2117 {
2118 // operation_aborted is expected if timer is canceled before
2119 // completion.
2120 if (ec != boost::asio::error::operation_aborted)
2121 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002122 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
2123 "GPIO_NAME", nmiOutConfig.lineName, "ERROR_MSG",
2124 ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002125 }
2126 }
2127 });
2128 // log to redfish
2129 nmiDiagIntLog();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002130 lg2::info("NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002131 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002132 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002133}
2134
2135static void nmiSourcePropertyMonitor(void)
2136{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002137 lg2::info("NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002138
Patrick Williams439b9c32022-07-22 19:26:53 -05002139 static std::unique_ptr<sdbusplus::bus::match_t> nmiSourceMatch =
2140 std::make_unique<sdbusplus::bus::match_t>(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002141 *conn,
2142 "type='signal',interface='org.freedesktop.DBus.Properties',"
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002143 "member='PropertiesChanged',"
2144 "arg0namespace='xyz.openbmc_project.Chassis.Control.NMISource'",
Patrick Williams439b9c32022-07-22 19:26:53 -05002145 [](sdbusplus::message_t& msg) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002146 std::string interfaceName;
2147 boost::container::flat_map<std::string, std::variant<bool, std::string>>
2148 propertiesChanged;
2149 std::string state;
2150 bool value = true;
2151 try
2152 {
2153 msg.read(interfaceName, propertiesChanged);
2154 if (propertiesChanged.begin()->first == "Enabled")
2155 {
2156 value = std::get<bool>(propertiesChanged.begin()->second);
2157 lg2::info("NMI Enabled propertiesChanged value: {VALUE}",
2158 "VALUE", value);
2159 nmiEnabled = value;
2160 if (nmiEnabled)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002161 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002162 nmiReset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002163 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05002164 }
2165 }
2166 catch (const std::exception& e)
2167 {
2168 lg2::error("Unable to read NMI source: {ERROR}", "ERROR", e);
2169 return;
2170 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002171 });
2172}
2173
2174static void setNmiSource()
2175{
2176 conn->async_method_call(
2177 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002178 if (ec)
2179 {
2180 lg2::error("failed to set NMI source");
2181 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002182 },
Chen Yugang303bd582019-11-01 08:45:06 +08002183 "xyz.openbmc_project.Settings",
2184 "/xyz/openbmc_project/Chassis/Control/NMISource",
2185 "org.freedesktop.DBus.Properties", "Set",
2186 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
Jason M. Bills418ce112021-09-08 15:15:05 -07002187 std::variant<std::string>{
2188 "xyz.openbmc_project.Chassis.Control.NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002189 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002190 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002191}
2192
Zev Weiss584aa132021-09-02 19:21:52 -05002193static void nmiButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002194{
Olivier FAURAXd7ea2832023-04-14 14:08:02 +00002195 // Don't handle event if host not running and config doesn't force it
2196 if (!nmiWhenPoweredOff &&
2197 getHostState(powerState) !=
2198 "xyz.openbmc_project.State.Host.HostState.Running")
2199 {
2200 return;
2201 }
Zev Weiss584aa132021-09-02 19:21:52 -05002202 nmiButtonIface->set_property("ButtonPressed", !state);
2203 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002204 {
2205 nmiButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002206 if (nmiButtonMasked)
2207 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002208 lg2::info("NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002209 }
2210 else
2211 {
2212 setNmiSource();
2213 }
2214 }
Zev Weiss584aa132021-09-02 19:21:52 -05002215}
2216
Zev Weiss584aa132021-09-02 19:21:52 -05002217static void idButtonHandler(bool state)
2218{
2219 idButtonIface->set_property("ButtonPressed", !state);
2220}
2221
Jason M. Billsfb957332021-01-28 13:18:46 -08002222static void pltRstHandler(bool pltRst)
2223{
2224 if (pltRst)
2225 {
2226 sendPowerControlEvent(Event::pltRstDeAssert);
2227 }
2228 else
2229 {
2230 sendPowerControlEvent(Event::pltRstAssert);
2231 }
2232}
2233
Patrick Williams439b9c32022-07-22 19:26:53 -05002234[[maybe_unused]] static void hostMiscHandler(sdbusplus::message_t& msg)
Jason M. Billsfb957332021-01-28 13:18:46 -08002235{
2236 std::string interfaceName;
2237 boost::container::flat_map<std::string, std::variant<bool>>
2238 propertiesChanged;
Jason M. Billsfb957332021-01-28 13:18:46 -08002239 try
2240 {
2241 msg.read(interfaceName, propertiesChanged);
2242 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002243 catch (const std::exception& e)
Jason M. Billsfb957332021-01-28 13:18:46 -08002244 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002245 lg2::error("Unable to read Host Misc status: {ERROR}", "ERROR", e);
Jason M. Billsfb957332021-01-28 13:18:46 -08002246 return;
2247 }
2248 if (propertiesChanged.empty())
2249 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002250 lg2::error("ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002251 return;
2252 }
2253
2254 for (auto& [property, value] : propertiesChanged)
2255 {
2256 if (property == "ESpiPlatformReset")
2257 {
2258 bool* pltRst = std::get_if<bool>(&value);
2259 if (pltRst == nullptr)
2260 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002261 lg2::error("{PROPERTY} property invalid", "PROPERTY", property);
Jason M. Billsfb957332021-01-28 13:18:46 -08002262 return;
2263 }
2264 pltRstHandler(*pltRst);
2265 }
2266 }
2267}
2268
Zev Weiss584aa132021-09-02 19:21:52 -05002269static void postCompleteHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002270{
Zev Weiss584aa132021-09-02 19:21:52 -05002271 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002272 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002273 sendPowerControlEvent(Event::postCompleteAssert);
Tim Lee86239182021-12-23 11:46:01 +08002274 setOperatingSystemState(OperatingSystemStateStage::Standby);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002275 }
2276 else
2277 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002278 sendPowerControlEvent(Event::postCompleteDeAssert);
Tim Lee86239182021-12-23 11:46:01 +08002279 setOperatingSystemState(OperatingSystemStateStage::Inactive);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002280 }
Zev Weiss584aa132021-09-02 19:21:52 -05002281}
2282
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302283static int loadConfigValues()
2284{
2285 const std::string configFilePath =
2286 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2287 ".json";
2288 std::ifstream configFile(configFilePath.c_str());
2289 if (!configFile.is_open())
2290 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002291 lg2::error("loadConfigValues: Cannot open config path \'{PATH}\'",
2292 "PATH", configFilePath);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302293 return -1;
2294 }
Zev Weiss1aa08b22021-09-15 17:06:20 -05002295 auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302296
Priyatharshan P70120512020-09-16 18:47:20 +05302297 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302298 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002299 lg2::error("Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302300 return -1;
2301 }
Priyatharshan P70120512020-09-16 18:47:20 +05302302 auto gpios = jsonData["gpio_configs"];
2303 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302304
Priyatharshan P70120512020-09-16 18:47:20 +05302305 ConfigData* tempGpioData;
2306
2307 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302308 {
Priyatharshan P70120512020-09-16 18:47:20 +05302309 if (!gpioConfig.contains("Name"))
2310 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002311 lg2::error("The 'Name' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302312 return -1;
2313 }
2314
2315 // Iterate through the powersignal map to check if the gpio json config
2316 // entry is valid
2317 std::string gpioName = gpioConfig["Name"];
2318 auto signalMapIter = powerSignalMap.find(gpioName);
2319 if (signalMapIter == powerSignalMap.end())
2320 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002321 lg2::error(
2322 "{GPIO_NAME} is not a recognized power-control signal name",
2323 "GPIO_NAME", gpioName);
Priyatharshan P70120512020-09-16 18:47:20 +05302324 return -1;
2325 }
2326
2327 // assign the power signal name to the corresponding structure reference
2328 // from map then fillup the structure with coressponding json config
2329 // value
2330 tempGpioData = signalMapIter->second;
2331 tempGpioData->name = gpioName;
2332
2333 if (!gpioConfig.contains("Type"))
2334 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002335 lg2::error("The \'Type\' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302336 return -1;
2337 }
2338
2339 std::string signalType = gpioConfig["Type"];
2340 if (signalType == "GPIO")
2341 {
2342 tempGpioData->type = ConfigType::GPIO;
2343 }
2344 else if (signalType == "DBUS")
2345 {
2346 tempGpioData->type = ConfigType::DBUS;
2347 }
2348 else
2349 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002350 lg2::error("{TYPE} is not a recognized power-control signal type",
2351 "TYPE", signalType);
Priyatharshan P70120512020-09-16 18:47:20 +05302352 return -1;
2353 }
2354
2355 if (tempGpioData->type == ConfigType::GPIO)
2356 {
2357 if (gpioConfig.contains("LineName"))
2358 {
2359 tempGpioData->lineName = gpioConfig["LineName"];
2360 }
2361 else
2362 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002363 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002364 "The \'LineName\' field must be defined for GPIO configuration");
Priyatharshan P70120512020-09-16 18:47:20 +05302365 return -1;
2366 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002367 if (gpioConfig.contains("Polarity"))
2368 {
2369 std::string polarity = gpioConfig["Polarity"];
2370 if (polarity == "ActiveLow")
2371 {
2372 tempGpioData->polarity = false;
2373 }
2374 else if (polarity == "ActiveHigh")
2375 {
2376 tempGpioData->polarity = true;
2377 }
2378 else
2379 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002380 lg2::error(
2381 "Polarity defined but not properly setup. Please only ActiveHigh or ActiveLow. Currently set to {POLARITY}",
2382 "POLARITY", polarity);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002383 return -1;
2384 }
2385 }
2386 else
2387 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002388 lg2::error("Polarity field not found for {GPIO_NAME}",
2389 "GPIO_NAME", tempGpioData->lineName);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002390 return -1;
2391 }
Priyatharshan P70120512020-09-16 18:47:20 +05302392 }
2393 else
2394 {
2395 // if dbus based gpio config is defined read and update the dbus
2396 // params corresponding to the gpio config instance
2397 for (auto& [key, dbusParamName] : dbusParams)
2398 {
Logananth Sundararaja4308042021-10-20 11:52:05 +05302399 if (!gpioConfig.contains(dbusParamName))
Priyatharshan P70120512020-09-16 18:47:20 +05302400 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002401 lg2::error(
2402 "The {DBUS_NAME} field must be defined for Dbus configuration ",
2403 "DBUS_NAME", dbusParamName);
Priyatharshan P70120512020-09-16 18:47:20 +05302404 return -1;
2405 }
2406 }
Logananth Sundararaja4308042021-10-20 11:52:05 +05302407 tempGpioData->dbusName =
2408 gpioConfig[dbusParams[DbusConfigType::name]];
2409 tempGpioData->path = gpioConfig[dbusParams[DbusConfigType::path]];
Priyatharshan P70120512020-09-16 18:47:20 +05302410 tempGpioData->interface =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302411 gpioConfig[dbusParams[DbusConfigType::interface]];
Priyatharshan P70120512020-09-16 18:47:20 +05302412 tempGpioData->lineName =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302413 gpioConfig[dbusParams[DbusConfigType::property]];
Priyatharshan P70120512020-09-16 18:47:20 +05302414 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302415 }
2416
Priyatharshan P70120512020-09-16 18:47:20 +05302417 // read and store the timer values from json config to Timer Map
2418 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302419 {
Priyatharshan P70120512020-09-16 18:47:20 +05302420 if (timers.contains(key.c_str()))
2421 {
2422 timerValue = timers[key.c_str()];
2423 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302424 }
2425
Olivier FAURAXd7ea2832023-04-14 14:08:02 +00002426 // If "events_configs" key is not in json config, fallback to {}
2427 auto events = jsonData.value(
2428 "event_configs", nlohmann::json(nlohmann::json::value_t::object));
2429 if (events)
2430 {
2431 nmiWhenPoweredOff = events.value("NMIWhenPoweredOff", true);
2432 }
2433
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302434 return 0;
2435}
Zev Weissa8f116a2021-09-01 21:08:30 -05002436
Patrick Williams439b9c32022-07-22 19:26:53 -05002437static bool getDbusMsgGPIOState(sdbusplus::message_t& msg,
Zev Weissa8f116a2021-09-01 21:08:30 -05002438 const std::string& lineName, bool& value)
2439{
2440 std::string thresholdInterface;
2441 std::string event;
2442 boost::container::flat_map<std::string, std::variant<bool>>
2443 propertiesChanged;
2444 try
2445 {
2446 msg.read(thresholdInterface, propertiesChanged);
2447 if (propertiesChanged.empty())
2448 {
2449 return false;
2450 }
2451
2452 event = propertiesChanged.begin()->first;
2453 if (event.empty() || event != lineName)
2454 {
2455 return false;
2456 }
2457
2458 value = std::get<bool>(propertiesChanged.begin()->second);
2459 return true;
2460 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002461 catch (const std::exception& e)
Zev Weissa8f116a2021-09-01 21:08:30 -05002462 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002463 lg2::error(
2464 "exception while reading dbus property \'{DBUS_NAME}\': {ERROR}",
2465 "DBUS_NAME", lineName, "ERROR", e);
Zev Weissa8f116a2021-09-01 21:08:30 -05002466 return false;
2467 }
2468}
2469
Patrick Williams439b9c32022-07-22 19:26:53 -05002470static sdbusplus::bus::match_t
Zev Weissa8f116a2021-09-01 21:08:30 -05002471 dbusGPIOMatcher(const ConfigData& cfg, std::function<void(bool)> onMatch)
2472{
Patrick Williams48aa1f02023-05-10 07:50:30 -05002473 auto pulseEventMatcherCallback =
2474 [&cfg, onMatch](sdbusplus::message_t& msg) {
Patrick Williams439b9c32022-07-22 19:26:53 -05002475 bool value = false;
2476 if (!getDbusMsgGPIOState(msg, cfg.lineName, value))
2477 {
2478 return;
2479 }
2480 onMatch(value);
2481 };
Zev Weissa8f116a2021-09-01 21:08:30 -05002482
Patrick Williams439b9c32022-07-22 19:26:53 -05002483 return sdbusplus::bus::match_t(
2484 static_cast<sdbusplus::bus_t&>(*conn),
Zev Weissa8f116a2021-09-01 21:08:30 -05002485 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2486 "PropertiesChanged',arg0='" +
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302487 cfg.interface + "'",
Zev Weissa8f116a2021-09-01 21:08:30 -05002488 std::move(pulseEventMatcherCallback));
2489}
2490
Priyatharshan P70120512020-09-16 18:47:20 +05302491int getProperty(ConfigData& configData)
2492{
2493 auto method = conn->new_method_call(
2494 configData.dbusName.c_str(), configData.path.c_str(),
2495 "org.freedesktop.DBus.Properties", "Get");
2496 method.append(configData.interface.c_str(), configData.lineName.c_str());
2497
2498 auto reply = conn->call(method);
2499 if (reply.is_method_error())
2500 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002501 lg2::error(
2502 "Error reading {PROPERTY} D-Bus property on interface {INTERFACE} and path {PATH}",
2503 "PROPERTY", configData.lineName, "INTERFACE", configData.interface,
2504 "PATH", configData.path);
Priyatharshan P70120512020-09-16 18:47:20 +05302505 return -1;
2506 }
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302507 std::variant<bool> resp;
Priyatharshan P70120512020-09-16 18:47:20 +05302508 reply.read(resp);
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302509 auto respValue = std::get_if<bool>(&resp);
Priyatharshan P70120512020-09-16 18:47:20 +05302510 if (!respValue)
2511 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002512 lg2::error("Error: {PROPERTY} D-Bus property is not the expected type",
2513 "PROPERTY", configData.lineName);
Priyatharshan P70120512020-09-16 18:47:20 +05302514 return -1;
2515 }
2516 return (*respValue);
2517}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002518} // namespace power_control
2519
2520int main(int argc, char* argv[])
2521{
Lei YU92caa4c2021-02-23 16:59:25 +08002522 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05302523
2524 if (argc > 1)
2525 {
2526 node = argv[1];
2527 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002528 lg2::info("Start Chassis power control service for host : {NODE}", "NODE",
2529 node);
Priyatharshan P70120512020-09-16 18:47:20 +05302530
Lei YU92caa4c2021-02-23 16:59:25 +08002531 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002532
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302533 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08002534 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302535 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002536 lg2::error("Host{NODE}: Error in Parsing...", "NODE", node);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302537 }
Naveen Mosesec972d82021-07-16 21:19:23 +05302538 /* Currently for single host based systems additional busname is added
2539 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
2540 Going forward for single hosts the old bus name without zero numbering
2541 will be removed when all other applications adapted to the
2542 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
2543
2544 if (node == "0")
2545 {
2546 // Request all the dbus names
2547 conn->request_name(hostDbusName.c_str());
2548 conn->request_name(chassisDbusName.c_str());
2549 conn->request_name(osDbusName.c_str());
2550 conn->request_name(buttonDbusName.c_str());
2551 conn->request_name(nmiDbusName.c_str());
2552 conn->request_name(rstCauseDbusName.c_str());
2553 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302554
Zev Weissc4005bd2021-09-01 22:30:23 -05002555 hostDbusName += node;
2556 chassisDbusName += node;
2557 osDbusName += node;
2558 buttonDbusName += node;
2559 nmiDbusName += node;
2560 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002561
Priyatharshan P70120512020-09-16 18:47:20 +05302562 // Request all the dbus names
2563 conn->request_name(hostDbusName.c_str());
2564 conn->request_name(chassisDbusName.c_str());
2565 conn->request_name(osDbusName.c_str());
2566 conn->request_name(buttonDbusName.c_str());
2567 conn->request_name(nmiDbusName.c_str());
2568 conn->request_name(rstCauseDbusName.c_str());
2569
2570 if (sioPwrGoodConfig.lineName.empty() ||
2571 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05302572 {
Lei YU92caa4c2021-02-23 16:59:25 +08002573 sioEnabled = false;
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002574 lg2::info("SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05302575 }
2576
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002577 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302578 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002579 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002580 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302581 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302582 {
2583 return -1;
2584 }
2585 }
Priyatharshan P70120512020-09-16 18:47:20 +05302586 else if (powerOkConfig.type == ConfigType::DBUS)
2587 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002588 static sdbusplus::bus::match_t powerOkEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002589 power_control::dbusGPIOMatcher(powerOkConfig, psPowerOKHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302590 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302591 else
2592 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002593 lg2::error("PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002594 return -1;
2595 }
2596
Lei YU92caa4c2021-02-23 16:59:25 +08002597 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002598 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05302599 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302600 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302601 {
Priyatharshan P70120512020-09-16 18:47:20 +05302602 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002603 sioPowerGoodHandler, sioPowerGoodLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302604 sioPowerGoodEvent))
2605 {
2606 return -1;
2607 }
2608 }
2609 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
2610 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002611 static sdbusplus::bus::match_t sioPwrGoodEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002612 power_control::dbusGPIOMatcher(sioPwrGoodConfig,
2613 sioPowerGoodHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302614 }
2615 else
2616 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002617 lg2::error(
Priyatharshan P70120512020-09-16 18:47:20 +05302618 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302619 return -1;
2620 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002621
Priyatharshan P19c47a32020-08-12 18:16:43 +05302622 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302623 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302624 {
Priyatharshan P70120512020-09-16 18:47:20 +05302625 if (!requestGPIOEvents(sioOnControlConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002626 sioOnControlHandler, sioOnControlLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302627 sioOnControlEvent))
2628 {
2629 return -1;
2630 }
2631 }
2632 else if (sioOnControlConfig.type == ConfigType::DBUS)
2633 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002634 static sdbusplus::bus::match_t sioOnControlEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002635 power_control::dbusGPIOMatcher(sioOnControlConfig,
2636 sioOnControlHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302637 }
2638 else
2639 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002640 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002641 "sioOnControl name should be configured from jsonconfig file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302642 return -1;
2643 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002644
Priyatharshan P19c47a32020-08-12 18:16:43 +05302645 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302646 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302647 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002648 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
Priyatharshan P70120512020-09-16 18:47:20 +05302649 sioS5Line, sioS5Event))
2650 {
2651 return -1;
2652 }
2653 }
2654 else if (sioS5Config.type == ConfigType::DBUS)
2655 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002656 static sdbusplus::bus::match_t sioS5EventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002657 power_control::dbusGPIOMatcher(sioS5Config, sioS5Handler);
Priyatharshan P70120512020-09-16 18:47:20 +05302658 }
2659 else
2660 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002661 lg2::error("sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302662 return -1;
2663 }
2664 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002665
2666 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302667 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002668 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002669 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
2670 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302671 {
2672 return -1;
2673 }
2674 }
Priyatharshan P70120512020-09-16 18:47:20 +05302675 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302676 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002677 static sdbusplus::bus::match_t powerButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002678 power_control::dbusGPIOMatcher(powerButtonConfig,
2679 powerButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002680 }
2681
2682 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302683 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002684 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002685 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
2686 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302687 {
2688 return -1;
2689 }
2690 }
Priyatharshan P70120512020-09-16 18:47:20 +05302691 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302692 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002693 static sdbusplus::bus::match_t resetButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002694 power_control::dbusGPIOMatcher(resetButtonConfig,
2695 resetButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002696 }
2697
2698 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302699 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302700 {
Priyatharshan P70120512020-09-16 18:47:20 +05302701 if (!nmiButtonConfig.lineName.empty())
2702 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002703 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302704 nmiButtonLine, nmiButtonEvent);
2705 }
2706 }
2707 else if (nmiButtonConfig.type == ConfigType::DBUS)
2708 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002709 static sdbusplus::bus::match_t nmiButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002710 power_control::dbusGPIOMatcher(nmiButtonConfig, nmiButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302711 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002712
2713 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302714 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302715 {
Priyatharshan P70120512020-09-16 18:47:20 +05302716 if (!idButtonConfig.lineName.empty())
2717 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002718 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302719 idButtonLine, idButtonEvent);
2720 }
2721 }
2722 else if (idButtonConfig.type == ConfigType::DBUS)
2723 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002724 static sdbusplus::bus::match_t idButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002725 power_control::dbusGPIOMatcher(idButtonConfig, idButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302726 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002727
Jason M. Billsfb957332021-01-28 13:18:46 -08002728#ifdef USE_PLT_RST
Patrick Williams439b9c32022-07-22 19:26:53 -05002729 sdbusplus::bus::match_t pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08002730 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08002731 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2732 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08002733 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08002734#endif
2735
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002736 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302737 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002738 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002739 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
2740 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302741 {
2742 return -1;
2743 }
2744 }
Priyatharshan P70120512020-09-16 18:47:20 +05302745 else if (postCompleteConfig.type == ConfigType::DBUS)
2746 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002747 static sdbusplus::bus::match_t postCompleteEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002748 power_control::dbusGPIOMatcher(postCompleteConfig,
2749 postCompleteHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302750 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302751 else
2752 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002753 lg2::error(
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002754 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002755 return -1;
2756 }
2757
2758 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05302759 if (!nmiOutConfig.lineName.empty())
2760 {
Jian Zhang461a1662022-09-22 11:29:01 +08002761 setGPIOOutput(nmiOutConfig.lineName, !nmiOutConfig.polarity,
2762 nmiOutLine);
Priyatharshan P70120512020-09-16 18:47:20 +05302763 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002764
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002765 // Initialize POWER_OUT and RESET_OUT GPIO.
2766 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05302767 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002768 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002769 if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
2770 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302771 {
2772 return -1;
2773 }
2774 }
2775 else
2776 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002777 lg2::error("powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002778 return -1;
2779 }
2780
Priyatharshan P70120512020-09-16 18:47:20 +05302781 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002782 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002783 if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
2784 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302785 {
2786 return -1;
2787 }
2788 }
2789 else
2790 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002791 lg2::error("ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002792 return -1;
2793 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002794 // Release line
2795 line.reset();
2796
Matt Simmering58e379d2022-09-23 14:45:50 -07002797 // Initialize the power state and operating system state
Lei YU92caa4c2021-02-23 16:59:25 +08002798 powerState = PowerState::off;
Matt Simmering58e379d2022-09-23 14:45:50 -07002799 operatingSystemState = OperatingSystemStateStage::Inactive;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002800 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05302801
2802 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002803 {
Jean-Marie Verdun61b4a5b2021-09-19 08:53:28 -04002804 if (psPowerOKLine.get_value() > 0 ||
Lei YUa37c2472021-09-26 15:57:12 +08002805 (sioEnabled &&
2806 (sioPowerGoodLine.get_value() == sioPwrGoodConfig.polarity)))
Priyatharshan P70120512020-09-16 18:47:20 +05302807 {
2808 powerState = PowerState::on;
2809 }
2810 }
2811 else
2812 {
2813 if (getProperty(powerOkConfig))
2814 {
2815 powerState = PowerState::on;
2816 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002817 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002818 // Check if we need to start the Power Restore policy
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03002819 if (powerState != PowerState::on)
2820 {
2821 powerRestore.run();
2822 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002823
Lei YU92caa4c2021-02-23 16:59:25 +08002824 if (nmiOutLine)
2825 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002826
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002827 lg2::info("Initializing power state.");
Lei YU92caa4c2021-02-23 16:59:25 +08002828 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002829
2830 // Power Control Service
2831 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002832 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002833
2834 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05302835 hostIface =
2836 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
2837 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002838 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08002839 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002840 "RequestedHostTransition",
2841 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2842 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002843 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2844 {
2845 // if power button is masked, ignore this
2846 if (!powerButtonMask)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002847 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002848 sendPowerControlEvent(Event::gracefulPowerOffRequest);
2849 addRestartCause(RestartCause::command);
Jason M. Billse7520ba2020-01-31 11:19:03 -08002850 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002851 else
2852 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002853 lg2::info("Power Button Masked.");
2854 throw std::invalid_argument("Transition Request Masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002855 return 0;
2856 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05002857 }
2858 else if (requested == "xyz.openbmc_project.State.Host.Transition.On")
2859 {
2860 // if power button is masked, ignore this
2861 if (!powerButtonMask)
2862 {
2863 sendPowerControlEvent(Event::powerOnRequest);
2864 addRestartCause(RestartCause::command);
2865 }
2866 else
2867 {
2868 lg2::info("Power Button Masked.");
2869 throw std::invalid_argument("Transition Request Masked");
2870 return 0;
2871 }
2872 }
2873 else if (requested ==
2874 "xyz.openbmc_project.State.Host.Transition.Reboot")
2875 {
2876 // if power button is masked, ignore this
2877 if (!powerButtonMask)
2878 {
2879 sendPowerControlEvent(Event::powerCycleRequest);
2880 addRestartCause(RestartCause::command);
2881 }
2882 else
2883 {
2884 lg2::info("Power Button Masked.");
2885 throw std::invalid_argument("Transition Request Masked");
2886 return 0;
2887 }
2888 }
2889 else if (requested ==
2890 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot")
2891 {
2892 // if reset button is masked, ignore this
2893 if (!resetButtonMask)
2894 {
2895 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
2896 addRestartCause(RestartCause::command);
2897 }
2898 else
2899 {
2900 lg2::info("Reset Button Masked.");
2901 throw std::invalid_argument("Transition Request Masked");
2902 return 0;
2903 }
2904 }
2905 else if (requested ==
2906 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot")
2907 {
2908 // if reset button is masked, ignore this
2909 if (!resetButtonMask)
2910 {
2911 sendPowerControlEvent(Event::resetRequest);
2912 addRestartCause(RestartCause::command);
2913 }
2914 else
2915 {
2916 lg2::info("Reset Button Masked.");
2917 throw std::invalid_argument("Transition Request Masked");
2918 return 0;
2919 }
2920 }
2921 else
2922 {
2923 lg2::error("Unrecognized host state transition request.");
2924 throw std::invalid_argument("Unrecognized Transition Request");
2925 return 0;
2926 }
2927 resp = requested;
2928 return 1;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002929 });
Lei YU92caa4c2021-02-23 16:59:25 +08002930 hostIface->register_property("CurrentHostState",
2931 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002932
Lei YU92caa4c2021-02-23 16:59:25 +08002933 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002934
2935 // Chassis Control Service
2936 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002937 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002938
2939 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002940 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05302941 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002942 "xyz.openbmc_project.State.Chassis");
2943
Lei YU92caa4c2021-02-23 16:59:25 +08002944 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002945 "RequestedPowerTransition",
2946 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
2947 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002948 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
2949 {
2950 // if power button is masked, ignore this
2951 if (!powerButtonMask)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002952 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002953 sendPowerControlEvent(Event::powerOffRequest);
2954 addRestartCause(RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002955 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002956 else
2957 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002958 lg2::info("Power Button Masked.");
2959 throw std::invalid_argument("Transition Request Masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002960 return 0;
2961 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05002962 }
2963 else if (requested == "xyz.openbmc_project.State.Chassis.Transition.On")
2964 {
2965 // if power button is masked, ignore this
2966 if (!powerButtonMask)
2967 {
2968 sendPowerControlEvent(Event::powerOnRequest);
2969 addRestartCause(RestartCause::command);
2970 }
2971 else
2972 {
2973 lg2::info("Power Button Masked.");
2974 throw std::invalid_argument("Transition Request Masked");
2975 return 0;
2976 }
2977 }
2978 else if (requested ==
2979 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2980 {
2981 // if power button is masked, ignore this
2982 if (!powerButtonMask)
2983 {
2984 sendPowerControlEvent(Event::powerCycleRequest);
2985 addRestartCause(RestartCause::command);
2986 }
2987 else
2988 {
2989 lg2::info("Power Button Masked.");
2990 throw std::invalid_argument("Transition Request Masked");
2991 return 0;
2992 }
2993 }
2994 else
2995 {
2996 lg2::error("Unrecognized chassis state transition request.");
2997 throw std::invalid_argument("Unrecognized Transition Request");
2998 return 0;
2999 }
3000 resp = requested;
3001 return 1;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003002 });
Lei YU92caa4c2021-02-23 16:59:25 +08003003 chassisIface->register_property("CurrentPowerState",
3004 std::string(getChassisState(powerState)));
3005 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003006
Lei YU92caa4c2021-02-23 16:59:25 +08003007 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003008
Vijay Khemka04175c22020-10-09 14:28:11 -07003009#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003010 // Chassis System Service
3011 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003012 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003013
3014 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003015 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003016 "/xyz/openbmc_project/state/chassis_system0",
3017 "xyz.openbmc_project.State.Chassis");
3018
Lei YU92caa4c2021-02-23 16:59:25 +08003019 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003020 "RequestedPowerTransition",
3021 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3022 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003023 if (requested ==
3024 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3025 {
3026 systemReset();
3027 addRestartCause(RestartCause::command);
3028 }
3029 else
3030 {
3031 lg2::error("Unrecognized chassis system state transition request.");
3032 throw std::invalid_argument("Unrecognized Transition Request");
3033 return 0;
3034 }
3035 resp = requested;
3036 return 1;
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003037 });
Lei YU92caa4c2021-02-23 16:59:25 +08003038 chassisSysIface->register_property(
3039 "CurrentPowerState", std::string(getChassisState(powerState)));
3040 chassisSysIface->register_property("LastStateChangeTime",
3041 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003042
Lei YU92caa4c2021-02-23 16:59:25 +08003043 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003044
Naveen Moses117c34e2021-05-26 20:10:51 +05303045 if (!slotPowerConfig.lineName.empty())
3046 {
3047 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3048 {
3049 return -1;
3050 }
3051
3052 slotPowerState = SlotPowerState::off;
3053 if (slotPowerLine.get_value() > 0)
3054 {
3055 slotPowerState = SlotPowerState::on;
3056 }
3057
3058 chassisSlotIface = chassisSysServer.add_interface(
3059 "/xyz/openbmc_project/state/chassis_system" + node,
3060 "xyz.openbmc_project.State.Chassis");
3061 chassisSlotIface->register_property(
3062 "RequestedPowerTransition",
3063 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3064 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003065 if (requested == "xyz.openbmc_project.State.Chassis.Transition.On")
3066 {
3067 slotPowerOn();
3068 }
3069 else if (requested ==
3070 "xyz.openbmc_project.State.Chassis.Transition.Off")
3071 {
3072 slotPowerOff();
3073 }
3074 else if (requested ==
3075 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3076 {
3077 slotPowerCycle();
3078 }
3079 else
3080 {
3081 lg2::error(
3082 "Unrecognized chassis system state transition request.\n");
3083 throw std::invalid_argument("Unrecognized Transition Request");
3084 return 0;
3085 }
3086 resp = requested;
3087 return 1;
Naveen Moses117c34e2021-05-26 20:10:51 +05303088 });
3089 chassisSlotIface->register_property(
3090 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3091 chassisSlotIface->register_property("LastStateChangeTime",
3092 getCurrentTimeMs());
3093 chassisSlotIface->initialize();
3094 }
3095#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003096 // Buttons Service
3097 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003098 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003099
Priyatharshan P70120512020-09-16 18:47:20 +05303100 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003101 {
Priyatharshan P70120512020-09-16 18:47:20 +05303102 // Power Button Interface
3103 power_control::powerButtonIface = buttonsServer.add_interface(
3104 "/xyz/openbmc_project/chassis/buttons/power",
3105 "xyz.openbmc_project.Chassis.Buttons");
3106
3107 powerButtonIface->register_property(
Patrick Williams48aa1f02023-05-10 07:50:30 -05003108 "ButtonMasked", false,
3109 [](const bool requested, bool& current) {
3110 if (requested)
3111 {
3112 if (powerButtonMask)
Priyatharshan P70120512020-09-16 18:47:20 +05303113 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003114 return 1;
Priyatharshan P70120512020-09-16 18:47:20 +05303115 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003116 if (!setGPIOOutput(powerOutConfig.lineName,
3117 !powerOutConfig.polarity, powerButtonMask))
Priyatharshan P70120512020-09-16 18:47:20 +05303118 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003119 throw std::runtime_error("Failed to request GPIO");
3120 return 0;
Priyatharshan P70120512020-09-16 18:47:20 +05303121 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003122 lg2::info("Power Button Masked.");
3123 }
3124 else
3125 {
3126 if (!powerButtonMask)
3127 {
3128 return 1;
3129 }
3130 lg2::info("Power Button Un-masked");
3131 powerButtonMask.reset();
3132 }
3133 // Update the mask setting
3134 current = requested;
3135 return 1;
Priyatharshan P70120512020-09-16 18:47:20 +05303136 });
3137
3138 // Check power button state
3139 bool powerButtonPressed;
3140 if (powerButtonConfig.type == ConfigType::GPIO)
3141 {
3142 powerButtonPressed = powerButtonLine.get_value() == 0;
3143 }
3144 else
3145 {
3146 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3147 }
3148
3149 powerButtonIface->register_property("ButtonPressed",
3150 powerButtonPressed);
3151
3152 powerButtonIface->initialize();
3153 }
3154
3155 if (!resetButtonConfig.lineName.empty())
3156 {
3157 // Reset Button Interface
3158
Lei YU92caa4c2021-02-23 16:59:25 +08003159 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003160 "/xyz/openbmc_project/chassis/buttons/reset",
3161 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003162
Lei YU92caa4c2021-02-23 16:59:25 +08003163 resetButtonIface->register_property(
Patrick Williams48aa1f02023-05-10 07:50:30 -05003164 "ButtonMasked", false,
3165 [](const bool requested, bool& current) {
3166 if (requested)
3167 {
3168 if (resetButtonMask)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003169 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003170 return 1;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003171 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003172 if (!setGPIOOutput(resetOutConfig.lineName,
3173 !resetOutConfig.polarity, resetButtonMask))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003174 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003175 throw std::runtime_error("Failed to request GPIO");
3176 return 0;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003177 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003178 lg2::info("Reset Button Masked.");
3179 }
3180 else
3181 {
3182 if (!resetButtonMask)
3183 {
3184 return 1;
3185 }
3186 lg2::info("Reset Button Un-masked");
3187 resetButtonMask.reset();
3188 }
3189 // Update the mask setting
3190 current = requested;
3191 return 1;
John Wang6c090072020-09-30 13:32:16 +08003192 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003193
John Wang6c090072020-09-30 13:32:16 +08003194 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303195 bool resetButtonPressed;
3196 if (resetButtonConfig.type == ConfigType::GPIO)
3197 {
3198 resetButtonPressed = resetButtonLine.get_value() == 0;
3199 }
3200 else
3201 {
3202 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3203 }
3204
Lei YU92caa4c2021-02-23 16:59:25 +08003205 resetButtonIface->register_property("ButtonPressed",
3206 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003207
Lei YU92caa4c2021-02-23 16:59:25 +08003208 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003209 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003210
Lei YU92caa4c2021-02-23 16:59:25 +08003211 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003212 {
3213 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003214 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003215 "/xyz/openbmc_project/chassis/buttons/nmi",
3216 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003217
Lei YU92caa4c2021-02-23 16:59:25 +08003218 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003219 "ButtonMasked", false, [](const bool requested, bool& current) {
Lei YU92caa4c2021-02-23 16:59:25 +08003220 if (nmiButtonMasked == requested)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003221 {
3222 // NMI button mask is already set as requested, so no change
3223 return 1;
3224 }
3225 if (requested)
3226 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003227 lg2::info("NMI Button Masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003228 nmiButtonMasked = true;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003229 }
3230 else
3231 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003232 lg2::info("NMI Button Un-masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003233 nmiButtonMasked = false;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003234 }
3235 // Update the mask setting
Lei YU92caa4c2021-02-23 16:59:25 +08003236 current = nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003237 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003238 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003239
Vijay Khemka33a532d2019-11-14 16:50:35 -08003240 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303241 bool nmiButtonPressed;
3242 if (nmiButtonConfig.type == ConfigType::GPIO)
3243 {
3244 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3245 }
3246 else
3247 {
3248 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3249 }
3250
Lei YU92caa4c2021-02-23 16:59:25 +08003251 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003252
Lei YU92caa4c2021-02-23 16:59:25 +08003253 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003254 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003255
Lei YU92caa4c2021-02-23 16:59:25 +08003256 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003257 {
3258 // NMI out Service
3259 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003260 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003261
Vijay Khemka33a532d2019-11-14 16:50:35 -08003262 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303263 nmiOutIface = nmiOutServer.add_interface(
3264 "/xyz/openbmc_project/control/host" + node + "/nmi",
3265 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003266 nmiOutIface->register_method("NMI", nmiReset);
3267 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003268 }
Chen Yugang174ec662019-08-19 19:58:49 +08003269
Lei YU92caa4c2021-02-23 16:59:25 +08003270 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003271 {
3272 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003273 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003274 "/xyz/openbmc_project/chassis/buttons/id",
3275 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003276
Vijay Khemka33a532d2019-11-14 16:50:35 -08003277 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303278 bool idButtonPressed;
3279 if (idButtonConfig.type == ConfigType::GPIO)
3280 {
3281 idButtonPressed = idButtonLine.get_value() == 0;
3282 }
3283 else
3284 {
3285 idButtonPressed = getProperty(idButtonConfig) == 0;
3286 }
3287
Lei YU92caa4c2021-02-23 16:59:25 +08003288 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003289
Lei YU92caa4c2021-02-23 16:59:25 +08003290 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003291 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003292
3293 // OS State Service
3294 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003295 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003296
3297 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003298 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003299 "/xyz/openbmc_project/state/os",
3300 "xyz.openbmc_project.State.OperatingSystem.Status");
3301
3302 // Get the initial OS state based on POST complete
3303 // 0: Asserted, OS state is "Standby" (ready to boot)
3304 // 1: De-Asserted, OS state is "Inactive"
Tim Lee86239182021-12-23 11:46:01 +08003305 OperatingSystemStateStage osState;
Priyatharshan P70120512020-09-16 18:47:20 +05303306 if (postCompleteConfig.type == ConfigType::GPIO)
3307 {
Tim Lee86239182021-12-23 11:46:01 +08003308 osState = postCompleteLine.get_value() > 0
3309 ? OperatingSystemStateStage::Inactive
3310 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303311 }
3312 else
3313 {
Tim Lee86239182021-12-23 11:46:01 +08003314 osState = getProperty(postCompleteConfig) > 0
3315 ? OperatingSystemStateStage::Inactive
3316 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303317 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003318
Tim Lee86239182021-12-23 11:46:01 +08003319 osIface->register_property(
3320 "OperatingSystemState",
3321 std::string(getOperatingSystemStateStage(osState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003322
Lei YU92caa4c2021-02-23 16:59:25 +08003323 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003324
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003325 // Restart Cause Service
3326 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003327 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003328
3329 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003330 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303331 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003332 "xyz.openbmc_project.Control.Host.RestartCause");
3333
Lei YU92caa4c2021-02-23 16:59:25 +08003334 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003335 "RestartCause",
3336 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3337
Lei YU92caa4c2021-02-23 16:59:25 +08003338 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003339 "RequestedRestartCause",
3340 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3341 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003342 if (requested ==
3343 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3344 {
3345 addRestartCause(RestartCause::watchdog);
3346 }
3347 else
3348 {
3349 throw std::invalid_argument("Unrecognized RestartCause Request");
3350 return 0;
3351 }
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003352
Patrick Williams48aa1f02023-05-10 07:50:30 -05003353 lg2::info("RestartCause requested: {RESTART_CAUSE}", "RESTART_CAUSE",
3354 requested);
3355 resp = requested;
3356 return 1;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003357 });
3358
Lei YU92caa4c2021-02-23 16:59:25 +08003359 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003360
Lei YU92caa4c2021-02-23 16:59:25 +08003361 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003362
Lei YU92caa4c2021-02-23 16:59:25 +08003363 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003364
3365 return 0;
3366}