blob: 8ceac4fc246b8269f1758974f4ced5f8b9d41e9f [file] [log] [blame]
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001/*
2// Copyright (c) 2018-2019 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +030016#include "power_control.hpp"
17
Ed Tanousf61ca6f2019-08-15 15:09:05 -070018#include <sys/sysinfo.h>
19#include <systemd/sd-journal.h>
20
Ed Tanous744e9a92023-02-28 13:35:22 -080021#include <boost/asio/io_context.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070022#include <boost/asio/posix/stream_descriptor.hpp>
Jason M. Billse63dea02020-08-27 12:07:35 -070023#include <boost/asio/steady_timer.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070024#include <boost/container/flat_map.hpp>
Jason M. Bills7d4aaac2019-09-19 14:03:44 -070025#include <boost/container/flat_set.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070026#include <gpiod.hpp>
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053027#include <nlohmann/json.hpp>
Jason M. Billsc46ebb42021-11-10 11:41:31 -080028#include <phosphor-logging/lg2.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070029#include <sdbusplus/asio/object_server.hpp>
Vijay Khemka2b6f4422020-05-29 11:13:23 -070030
31#include <filesystem>
32#include <fstream>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070033#include <string_view>
34
35namespace power_control
36{
Ed Tanous744e9a92023-02-28 13:35:22 -080037static boost::asio::io_context io;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070038std::shared_ptr<sdbusplus::asio::connection> conn;
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +030039PersistentState appState;
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +030040PowerRestoreController powerRestore(io);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053041
42static std::string node = "0";
Andrei Kartashev3efcf372021-12-29 15:32:17 +030043static const std::string appName = "power-control";
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053044
Priyatharshan P70120512020-09-16 18:47:20 +053045enum class DbusConfigType
46{
47 name = 1,
48 path,
49 interface,
50 property
51};
52boost::container::flat_map<DbusConfigType, std::string> dbusParams = {
53 {DbusConfigType::name, "DbusName"},
54 {DbusConfigType::path, "Path"},
55 {DbusConfigType::interface, "Interface"},
56 {DbusConfigType::property, "Property"}};
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053057
Priyatharshan P70120512020-09-16 18:47:20 +053058enum class ConfigType
59{
60 GPIO = 1,
61 DBUS
62};
63
64struct ConfigData
65{
66 std::string name;
67 std::string lineName;
68 std::string dbusName;
69 std::string path;
70 std::string interface;
Jean-Marie Verdun50937e72021-08-31 09:15:49 -070071 bool polarity;
Priyatharshan P70120512020-09-16 18:47:20 +053072 ConfigType type;
73};
74
75static ConfigData powerOutConfig;
76static ConfigData powerOkConfig;
77static ConfigData resetOutConfig;
78static ConfigData nmiOutConfig;
79static ConfigData sioPwrGoodConfig;
80static ConfigData sioOnControlConfig;
81static ConfigData sioS5Config;
82static ConfigData postCompleteConfig;
83static ConfigData powerButtonConfig;
84static ConfigData resetButtonConfig;
85static ConfigData idButtonConfig;
86static ConfigData nmiButtonConfig;
Naveen Moses117c34e2021-05-26 20:10:51 +053087static ConfigData slotPowerConfig;
88
Priyatharshan P70120512020-09-16 18:47:20 +053089// map for storing list of gpio parameters whose config are to be read from x86
90// power control json config
91boost::container::flat_map<std::string, ConfigData*> powerSignalMap = {
92 {"PowerOut", &powerOutConfig},
93 {"PowerOk", &powerOkConfig},
94 {"ResetOut", &resetOutConfig},
95 {"NMIOut", &nmiOutConfig},
96 {"SioPowerGood", &sioPwrGoodConfig},
97 {"SioOnControl", &sioOnControlConfig},
98 {"SIOS5", &sioS5Config},
99 {"PostComplete", &postCompleteConfig},
100 {"PowerButton", &powerButtonConfig},
101 {"ResetButton", &resetButtonConfig},
102 {"IdButton", &idButtonConfig},
Naveen Moses117c34e2021-05-26 20:10:51 +0530103 {"NMIButton", &nmiButtonConfig},
104 {"SlotPower", &slotPowerConfig}};
Priyatharshan P70120512020-09-16 18:47:20 +0530105
106static std::string hostDbusName = "xyz.openbmc_project.State.Host";
107static std::string chassisDbusName = "xyz.openbmc_project.State.Chassis";
108static std::string osDbusName = "xyz.openbmc_project.State.OperatingSystem";
109static std::string buttonDbusName = "xyz.openbmc_project.Chassis.Buttons";
110static std::string nmiDbusName = "xyz.openbmc_project.Control.Host.NMI";
111static std::string rstCauseDbusName =
112 "xyz.openbmc_project.Control.Host.RestartCause";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700113static std::shared_ptr<sdbusplus::asio::dbus_interface> hostIface;
114static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700115#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -0700116static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSysIface;
Naveen Moses117c34e2021-05-26 20:10:51 +0530117static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSlotIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700118#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700119static std::shared_ptr<sdbusplus::asio::dbus_interface> powerButtonIface;
120static std::shared_ptr<sdbusplus::asio::dbus_interface> resetButtonIface;
121static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiButtonIface;
122static std::shared_ptr<sdbusplus::asio::dbus_interface> osIface;
123static std::shared_ptr<sdbusplus::asio::dbus_interface> idButtonIface;
Chen Yugang174ec662019-08-19 19:58:49 +0800124static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiOutIface;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700125static std::shared_ptr<sdbusplus::asio::dbus_interface> restartCauseIface;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700126
127static gpiod::line powerButtonMask;
128static gpiod::line resetButtonMask;
129static bool nmiButtonMasked = false;
Matt Simmering58e379d2022-09-23 14:45:50 -0700130#if IGNORE_SOFT_RESETS_DURING_POST
131static bool ignoreNextSoftReset = false;
132#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700133
Priyatharshan P70120512020-09-16 18:47:20 +0530134// This map contains all timer values that are to be read from json config
135boost::container::flat_map<std::string, int> TimerMap = {
Jason M. Billsaeefe042021-09-08 14:56:11 -0700136 {"PowerPulseMs", 200},
137 {"ForceOffPulseMs", 15000},
138 {"ResetPulseMs", 500},
139 {"PowerCycleMs", 5000},
140 {"SioPowerGoodWatchdogMs", 1000},
141 {"PsPowerOKWatchdogMs", 8000},
142 {"GracefulPowerOffS", (5 * 60)},
143 {"WarmResetCheckMs", 500},
144 {"PowerOffSaveMs", 7000},
Michal Orzeledd211e2022-10-28 13:10:16 +0200145 {"SlotPowerCycleMs", 200},
146 {"DbusGetPropertyRetry", 1000}};
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700147
148static bool nmiEnabled = true;
Olivier FAURAXd7ea2832023-04-14 14:08:02 +0000149static bool nmiWhenPoweredOff = true;
Priyatharshan P19c47a32020-08-12 18:16:43 +0530150static bool sioEnabled = true;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700151
152// Timers
153// Time holding GPIOs asserted
154static boost::asio::steady_timer gpioAssertTimer(io);
155// Time between off and on during a power cycle
156static boost::asio::steady_timer powerCycleTimer(io);
157// Time OS gracefully powering off
158static boost::asio::steady_timer gracefulPowerOffTimer(io);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700159// Time the warm reset check
160static boost::asio::steady_timer warmResetCheckTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700161// Time power supply power OK assertion on power-on
162static boost::asio::steady_timer psPowerOKWatchdogTimer(io);
163// Time SIO power good assertion on power-on
164static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io);
165// Time power-off state save for power loss tracking
166static boost::asio::steady_timer powerStateSaveTimer(io);
167// POH timer
168static boost::asio::steady_timer pohCounterTimer(io);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700169// Time when to allow restart cause updates
170static boost::asio::steady_timer restartCauseTimer(io);
Naveen Moses117c34e2021-05-26 20:10:51 +0530171static boost::asio::steady_timer slotPowerCycleTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700172
Michal Orzeledd211e2022-10-28 13:10:16 +0200173// Map containing timers used for D-Bus get-property retries
174static boost::container::flat_map<std::string, boost::asio::steady_timer>
175 dBusRetryTimers;
176
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700177// GPIO Lines and Event Descriptors
178static gpiod::line psPowerOKLine;
179static boost::asio::posix::stream_descriptor psPowerOKEvent(io);
180static gpiod::line sioPowerGoodLine;
181static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io);
182static gpiod::line sioOnControlLine;
183static boost::asio::posix::stream_descriptor sioOnControlEvent(io);
184static gpiod::line sioS5Line;
185static boost::asio::posix::stream_descriptor sioS5Event(io);
186static gpiod::line powerButtonLine;
187static boost::asio::posix::stream_descriptor powerButtonEvent(io);
188static gpiod::line resetButtonLine;
189static boost::asio::posix::stream_descriptor resetButtonEvent(io);
190static gpiod::line nmiButtonLine;
191static boost::asio::posix::stream_descriptor nmiButtonEvent(io);
192static gpiod::line idButtonLine;
193static boost::asio::posix::stream_descriptor idButtonEvent(io);
194static gpiod::line postCompleteLine;
195static boost::asio::posix::stream_descriptor postCompleteEvent(io);
196static gpiod::line nmiOutLine;
Naveen Moses117c34e2021-05-26 20:10:51 +0530197static gpiod::line slotPowerLine;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700198
199static constexpr uint8_t beepPowerFail = 8;
200
201static void beep(const uint8_t& beepPriority)
202{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800203 lg2::info("Beep with priority: {BEEP_PRIORITY}", "BEEP_PRIORITY",
204 beepPriority);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700205
206 conn->async_method_call(
207 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -0500208 if (ec)
209 {
210 lg2::error(
211 "beep returned error with async_method_call (ec = {ERROR_MSG})",
212 "ERROR_MSG", ec.message());
213 return;
214 }
Patrick Williamsd394c882023-10-20 11:18:44 -0500215 },
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700216 "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
217 "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
218}
219
Tim Lee86239182021-12-23 11:46:01 +0800220enum class OperatingSystemStateStage
221{
222 Inactive,
223 Standby,
224};
Matt Simmering58e379d2022-09-23 14:45:50 -0700225static OperatingSystemStateStage operatingSystemState;
Tim Lee86239182021-12-23 11:46:01 +0800226static constexpr std::string_view
227 getOperatingSystemStateStage(const OperatingSystemStateStage stage)
228{
229 switch (stage)
230 {
231 case OperatingSystemStateStage::Inactive:
232 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
233 break;
234 case OperatingSystemStateStage::Standby:
235 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Standby";
236 break;
237 default:
238 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
239 break;
240 }
241};
242static void setOperatingSystemState(const OperatingSystemStateStage stage)
243{
Matt Simmering58e379d2022-09-23 14:45:50 -0700244 operatingSystemState = stage;
245#if IGNORE_SOFT_RESETS_DURING_POST
246 // If POST complete has asserted set ignoreNextSoftReset to false to avoid
247 // masking soft resets after POST
248 if (operatingSystemState == OperatingSystemStateStage::Standby)
249 {
250 ignoreNextSoftReset = false;
251 }
252#endif
Tim Lee86239182021-12-23 11:46:01 +0800253 osIface->set_property("OperatingSystemState",
254 std::string(getOperatingSystemStateStage(stage)));
255
256 lg2::info("Moving os state to {STATE} stage", "STATE",
257 getOperatingSystemStateStage(stage));
258}
259
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700260enum class PowerState
261{
262 on,
263 waitForPSPowerOK,
264 waitForSIOPowerGood,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700265 off,
266 transitionToOff,
267 gracefulTransitionToOff,
268 cycleOff,
269 transitionToCycleOff,
270 gracefulTransitionToCycleOff,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700271 checkForWarmReset,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700272};
273static PowerState powerState;
274static std::string getPowerStateName(PowerState state)
275{
276 switch (state)
277 {
278 case PowerState::on:
279 return "On";
280 break;
281 case PowerState::waitForPSPowerOK:
282 return "Wait for Power Supply Power OK";
283 break;
284 case PowerState::waitForSIOPowerGood:
285 return "Wait for SIO Power Good";
286 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700287 case PowerState::off:
288 return "Off";
289 break;
290 case PowerState::transitionToOff:
291 return "Transition to Off";
292 break;
293 case PowerState::gracefulTransitionToOff:
294 return "Graceful Transition to Off";
295 break;
296 case PowerState::cycleOff:
297 return "Power Cycle Off";
298 break;
299 case PowerState::transitionToCycleOff:
300 return "Transition to Power Cycle Off";
301 break;
302 case PowerState::gracefulTransitionToCycleOff:
303 return "Graceful Transition to Power Cycle Off";
304 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700305 case PowerState::checkForWarmReset:
306 return "Check for Warm Reset";
307 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700308 default:
309 return "unknown state: " + std::to_string(static_cast<int>(state));
310 break;
311 }
312}
313static void logStateTransition(const PowerState state)
314{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800315 lg2::info("Host{HOST}: Moving to \"{STATE}\" state", "HOST", node, "STATE",
316 getPowerStateName(state));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700317}
318
319enum class Event
320{
321 psPowerOKAssert,
322 psPowerOKDeAssert,
323 sioPowerGoodAssert,
324 sioPowerGoodDeAssert,
325 sioS5Assert,
326 sioS5DeAssert,
Jason M. Billsfb957332021-01-28 13:18:46 -0800327 pltRstAssert,
328 pltRstDeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700329 postCompleteAssert,
330 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700331 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700332 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700333 powerCycleTimerExpired,
334 psPowerOKWatchdogTimerExpired,
335 sioPowerGoodWatchdogTimerExpired,
336 gracefulPowerOffTimerExpired,
337 powerOnRequest,
338 powerOffRequest,
339 powerCycleRequest,
340 resetRequest,
341 gracefulPowerOffRequest,
342 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700343 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700344};
345static std::string getEventName(Event event)
346{
347 switch (event)
348 {
349 case Event::psPowerOKAssert:
350 return "power supply power OK assert";
351 break;
352 case Event::psPowerOKDeAssert:
353 return "power supply power OK de-assert";
354 break;
355 case Event::sioPowerGoodAssert:
356 return "SIO power good assert";
357 break;
358 case Event::sioPowerGoodDeAssert:
359 return "SIO power good de-assert";
360 break;
361 case Event::sioS5Assert:
362 return "SIO S5 assert";
363 break;
364 case Event::sioS5DeAssert:
365 return "SIO S5 de-assert";
366 break;
Jason M. Billsfb957332021-01-28 13:18:46 -0800367 case Event::pltRstAssert:
368 return "PLT_RST assert";
369 break;
370 case Event::pltRstDeAssert:
371 return "PLT_RST de-assert";
372 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700373 case Event::postCompleteAssert:
374 return "POST Complete assert";
375 break;
376 case Event::postCompleteDeAssert:
377 return "POST Complete de-assert";
378 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700379 case Event::powerButtonPressed:
380 return "power button pressed";
381 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700382 case Event::resetButtonPressed:
383 return "reset button pressed";
384 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700385 case Event::powerCycleTimerExpired:
386 return "power cycle timer expired";
387 break;
388 case Event::psPowerOKWatchdogTimerExpired:
389 return "power supply power OK watchdog timer expired";
390 break;
391 case Event::sioPowerGoodWatchdogTimerExpired:
392 return "SIO power good watchdog timer expired";
393 break;
394 case Event::gracefulPowerOffTimerExpired:
395 return "graceful power-off timer expired";
396 break;
397 case Event::powerOnRequest:
398 return "power-on request";
399 break;
400 case Event::powerOffRequest:
401 return "power-off request";
402 break;
403 case Event::powerCycleRequest:
404 return "power-cycle request";
405 break;
406 case Event::resetRequest:
407 return "reset request";
408 break;
409 case Event::gracefulPowerOffRequest:
410 return "graceful power-off request";
411 break;
412 case Event::gracefulPowerCycleRequest:
413 return "graceful power-cycle request";
414 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700415 case Event::warmResetDetected:
416 return "warm reset detected";
417 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700418 default:
419 return "unknown event: " + std::to_string(static_cast<int>(event));
420 break;
421 }
422}
423static void logEvent(const std::string_view stateHandler, const Event event)
424{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800425 lg2::info("{STATE_HANDLER}: {EVENT} event received", "STATE_HANDLER",
426 stateHandler, "EVENT", getEventName(event));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700427}
428
429// Power state handlers
430static void powerStateOn(const Event event);
431static void powerStateWaitForPSPowerOK(const Event event);
432static void powerStateWaitForSIOPowerGood(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700433static void powerStateOff(const Event event);
434static void powerStateTransitionToOff(const Event event);
435static void powerStateGracefulTransitionToOff(const Event event);
436static void powerStateCycleOff(const Event event);
437static void powerStateTransitionToCycleOff(const Event event);
438static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700439static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700440
441static std::function<void(const Event)> getPowerStateHandler(PowerState state)
442{
443 switch (state)
444 {
445 case PowerState::on:
446 return powerStateOn;
447 break;
448 case PowerState::waitForPSPowerOK:
449 return powerStateWaitForPSPowerOK;
450 break;
451 case PowerState::waitForSIOPowerGood:
452 return powerStateWaitForSIOPowerGood;
453 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700454 case PowerState::off:
455 return powerStateOff;
456 break;
457 case PowerState::transitionToOff:
458 return powerStateTransitionToOff;
459 break;
460 case PowerState::gracefulTransitionToOff:
461 return powerStateGracefulTransitionToOff;
462 break;
463 case PowerState::cycleOff:
464 return powerStateCycleOff;
465 break;
466 case PowerState::transitionToCycleOff:
467 return powerStateTransitionToCycleOff;
468 break;
469 case PowerState::gracefulTransitionToCycleOff:
470 return powerStateGracefulTransitionToCycleOff;
471 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700472 case PowerState::checkForWarmReset:
473 return powerStateCheckForWarmReset;
474 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700475 default:
Zev Weiss047bcb52020-08-20 21:28:11 +0000476 return nullptr;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700477 break;
478 }
479};
480
481static void sendPowerControlEvent(const Event event)
482{
483 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
484 if (handler == nullptr)
485 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800486 lg2::error("Failed to find handler for power state: {STATE}", "STATE",
487 static_cast<int>(powerState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700488 return;
489 }
490 handler(event);
491}
492
493static uint64_t getCurrentTimeMs()
494{
495 struct timespec time = {};
496
497 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
498 {
499 return 0;
500 }
501 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
502 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
503
504 return currentTimeMs;
505}
506
507static constexpr std::string_view getHostState(const PowerState state)
508{
509 switch (state)
510 {
511 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700512 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700513 case PowerState::gracefulTransitionToCycleOff:
514 return "xyz.openbmc_project.State.Host.HostState.Running";
515 break;
516 case PowerState::waitForPSPowerOK:
517 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700518 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700519 case PowerState::transitionToOff:
520 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700521 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700522 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700523 return "xyz.openbmc_project.State.Host.HostState.Off";
524 break;
525 default:
526 return "";
527 break;
528 }
529};
530static constexpr std::string_view getChassisState(const PowerState state)
531{
532 switch (state)
533 {
534 case PowerState::on:
535 case PowerState::transitionToOff:
536 case PowerState::gracefulTransitionToOff:
537 case PowerState::transitionToCycleOff:
538 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700539 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700540 return "xyz.openbmc_project.State.Chassis.PowerState.On";
541 break;
542 case PowerState::waitForPSPowerOK:
543 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700544 case PowerState::off:
545 case PowerState::cycleOff:
546 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
547 break;
548 default:
549 return "";
550 break;
551 }
552};
Naveen Moses117c34e2021-05-26 20:10:51 +0530553#ifdef CHASSIS_SYSTEM_RESET
554enum class SlotPowerState
555{
556 on,
557 off,
558};
559static SlotPowerState slotPowerState;
560static constexpr std::string_view getSlotState(const SlotPowerState state)
561{
562 switch (state)
563 {
564 case SlotPowerState::on:
565 return "xyz.openbmc_project.State.Chassis.PowerState.On";
566 break;
567 case SlotPowerState::off:
568 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
569 break;
570 default:
571 return "";
572 break;
573 }
574};
575static void setSlotPowerState(const SlotPowerState state)
576{
577 slotPowerState = state;
578 chassisSlotIface->set_property("CurrentPowerState",
579 std::string(getSlotState(slotPowerState)));
580 chassisSlotIface->set_property("LastStateChangeTime", getCurrentTimeMs());
581}
582#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700583static void savePowerState(const PowerState state)
584{
585 powerStateSaveTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -0700586 std::chrono::milliseconds(TimerMap["PowerOffSaveMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700587 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
588 if (ec)
589 {
590 // operation_aborted is expected if timer is canceled before
591 // completion.
592 if (ec != boost::asio::error::operation_aborted)
593 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800594 lg2::error("Power-state save async_wait failed: {ERROR_MSG}",
595 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700596 }
597 return;
598 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300599 appState.set(PersistentState::Params::PowerState,
600 std::string{getChassisState(state)});
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700601 });
602}
603static void setPowerState(const PowerState state)
604{
605 powerState = state;
606 logStateTransition(state);
607
608 hostIface->set_property("CurrentHostState",
609 std::string(getHostState(powerState)));
610
611 chassisIface->set_property("CurrentPowerState",
612 std::string(getChassisState(powerState)));
613 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
614
615 // Save the power state for the restore policy
616 savePowerState(state);
617}
618
619enum class RestartCause
620{
621 command,
622 resetButton,
623 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700624 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700625 powerPolicyOn,
626 powerPolicyRestore,
627 softReset,
628};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700629static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700630static std::string getRestartCause(RestartCause cause)
631{
632 switch (cause)
633 {
634 case RestartCause::command:
635 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
636 break;
637 case RestartCause::resetButton:
638 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
639 break;
640 case RestartCause::powerButton:
641 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
642 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700643 case RestartCause::watchdog:
644 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
645 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700646 case RestartCause::powerPolicyOn:
Jason M. Bills418ce112021-09-08 15:15:05 -0700647 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyAlwaysOn";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700648 break;
649 case RestartCause::powerPolicyRestore:
Jason M. Bills418ce112021-09-08 15:15:05 -0700650 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyPreviousState";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700651 break;
652 case RestartCause::softReset:
653 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
654 break;
655 default:
656 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
657 break;
658 }
659}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700660static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700661{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700662 // Add this to the set of causes for this restart
663 causeSet.insert(cause);
664}
665static void clearRestartCause()
666{
667 // Clear the set for the next restart
668 causeSet.clear();
669}
670static void setRestartCauseProperty(const std::string& cause)
671{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800672 lg2::info("RestartCause set to {RESTART_CAUSE}", "RESTART_CAUSE", cause);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700673 restartCauseIface->set_property("RestartCause", cause);
674}
Rashmi RV89f61312020-01-22 15:41:50 +0530675
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300676#ifdef USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +0530677static void resetACBootProperty()
678{
679 if ((causeSet.contains(RestartCause::command)) ||
680 (causeSet.contains(RestartCause::softReset)))
681 {
682 conn->async_method_call(
683 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -0500684 if (ec)
685 {
686 lg2::error("failed to reset ACBoot property");
687 }
Patrick Williamsd394c882023-10-20 11:18:44 -0500688 },
Rashmi RV89f61312020-01-22 15:41:50 +0530689 "xyz.openbmc_project.Settings",
690 "/xyz/openbmc_project/control/host0/ac_boot",
691 "org.freedesktop.DBus.Properties", "Set",
692 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
693 std::variant<std::string>{"False"});
694 }
695}
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300696#endif // USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +0530697
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700698static void setRestartCause()
699{
700 // Determine the actual restart cause based on the set of causes
701 std::string restartCause =
702 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
703 if (causeSet.contains(RestartCause::watchdog))
704 {
705 restartCause = getRestartCause(RestartCause::watchdog);
706 }
707 else if (causeSet.contains(RestartCause::command))
708 {
709 restartCause = getRestartCause(RestartCause::command);
710 }
711 else if (causeSet.contains(RestartCause::resetButton))
712 {
713 restartCause = getRestartCause(RestartCause::resetButton);
714 }
715 else if (causeSet.contains(RestartCause::powerButton))
716 {
717 restartCause = getRestartCause(RestartCause::powerButton);
718 }
719 else if (causeSet.contains(RestartCause::powerPolicyOn))
720 {
721 restartCause = getRestartCause(RestartCause::powerPolicyOn);
722 }
723 else if (causeSet.contains(RestartCause::powerPolicyRestore))
724 {
725 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
726 }
727 else if (causeSet.contains(RestartCause::softReset))
728 {
Matt Simmering58e379d2022-09-23 14:45:50 -0700729#if IGNORE_SOFT_RESETS_DURING_POST
730 if (ignoreNextSoftReset)
731 {
732 ignoreNextSoftReset = false;
733 return;
734 }
735#endif
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700736 restartCause = getRestartCause(RestartCause::softReset);
737 }
738
739 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700740}
741
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700742static void systemPowerGoodFailedLog()
743{
744 sd_journal_send(
745 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
746 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
747 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700748 TimerMap["SioPowerGoodWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700749}
750
751static void psPowerOKFailedLog()
752{
753 sd_journal_send(
754 "MESSAGE=PowerControl: power supply power good failed to assert",
755 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
756 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700757 TimerMap["PsPowerOKWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700758}
759
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700760static void powerRestorePolicyLog()
761{
762 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
763 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
764 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
765}
766
767static void powerButtonPressLog()
768{
769 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
770 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
771 "OpenBMC.0.1.PowerButtonPressed", NULL);
772}
773
774static void resetButtonPressLog()
775{
776 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
777 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
778 "OpenBMC.0.1.ResetButtonPressed", NULL);
779}
780
781static void nmiButtonPressLog()
782{
783 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
784 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
785 "OpenBMC.0.1.NMIButtonPressed", NULL);
786}
787
788static void nmiDiagIntLog()
789{
790 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
791 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
792 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
793}
794
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300795PersistentState::PersistentState()
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700796{
797 // create the power control directory if it doesn't exist
798 std::error_code ec;
799 if (!(std::filesystem::create_directories(powerControlDir, ec)))
800 {
801 if (ec.value() != 0)
802 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800803 lg2::error("failed to create {DIR_NAME}: {ERROR_MSG}", "DIR_NAME",
804 powerControlDir.string(), "ERROR_MSG", ec.message());
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300805 throw std::runtime_error("Failed to create state directory");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700806 }
807 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300808
809 // read saved state, it's ok, if the file doesn't exists
810 std::ifstream appStateStream(powerControlDir / stateFile);
811 if (!appStateStream.is_open())
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700812 {
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300813 lg2::info("Cannot open state file \'{PATH}\'", "PATH",
814 std::string(powerControlDir / stateFile));
815 stateData = nlohmann::json({});
816 return;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700817 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300818 try
819 {
820 appStateStream >> stateData;
821 if (stateData.is_discarded())
822 {
823 lg2::info("Cannot parse state file \'{PATH}\'", "PATH",
824 std::string(powerControlDir / stateFile));
825 stateData = nlohmann::json({});
826 return;
827 }
828 }
829 catch (const std::exception& ex)
830 {
831 lg2::info("Cannot read state file \'{PATH}\'", "PATH",
832 std::string(powerControlDir / stateFile));
833 stateData = nlohmann::json({});
834 return;
835 }
836}
837PersistentState::~PersistentState()
838{
839 saveState();
840}
841const std::string PersistentState::get(Params parameter)
842{
843 auto val = stateData.find(getName(parameter));
844 if (val != stateData.end())
845 {
846 return val->get<std::string>();
847 }
848 return getDefault(parameter);
849}
850void PersistentState::set(Params parameter, const std::string& value)
851{
852 stateData[getName(parameter)] = value;
853 saveState();
854}
855
856const std::string PersistentState::getName(const Params parameter)
857{
858 switch (parameter)
859 {
860 case Params::PowerState:
861 return "PowerState";
862 }
863 return "";
864}
865const std::string PersistentState::getDefault(const Params parameter)
866{
867 switch (parameter)
868 {
869 case Params::PowerState:
870 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
871 }
872 return "";
873}
874void PersistentState::saveState()
875{
876 std::ofstream appStateStream(powerControlDir / stateFile, std::ios::trunc);
877 if (!appStateStream.is_open())
878 {
879 lg2::error("Cannot write state file \'{PATH}\'", "PATH",
880 std::string(powerControlDir / stateFile));
881 return;
882 }
883 appStateStream << stateData.dump(indentationSize);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700884}
885
Patrick Williams48aa1f02023-05-10 07:50:30 -0500886static constexpr const char* setingsService = "xyz.openbmc_project.Settings";
887static constexpr const char* powerRestorePolicyIface =
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300888 "xyz.openbmc_project.Control.Power.RestorePolicy";
889#ifdef USE_ACBOOT
Patrick Williams48aa1f02023-05-10 07:50:30 -0500890static constexpr const char* powerACBootObject =
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300891 "/xyz/openbmc_project/control/host0/ac_boot";
Patrick Williams48aa1f02023-05-10 07:50:30 -0500892static constexpr const char* powerACBootIface =
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300893 "xyz.openbmc_project.Common.ACBoot";
894#endif // USE_ACBOOT
895
896namespace match_rules = sdbusplus::bus::match::rules;
897
898static int powerRestoreConfigHandler(sd_bus_message* m, void* context,
899 sd_bus_error*)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700900{
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300901 if (context == nullptr || m == nullptr)
902 {
903 throw std::runtime_error("Invalid match");
904 }
Patrick Williams439b9c32022-07-22 19:26:53 -0500905 sdbusplus::message_t message(m);
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300906 PowerRestoreController* powerRestore =
907 static_cast<PowerRestoreController*>(context);
908
909 if (std::string(message.get_member()) == "InterfacesAdded")
910 {
911 sdbusplus::message::object_path path;
912 boost::container::flat_map<std::string, dbusPropertiesList> data;
913
914 message.read(path, data);
915
916 for (auto& [iface, properties] : data)
917 {
918 if ((iface == powerRestorePolicyIface)
919#ifdef USE_ACBOOT
920 || (iface == powerACBootIface)
921#endif // USE_ACBOOT
922 )
923 {
924 powerRestore->setProperties(properties);
925 }
926 }
927 }
928 else if (std::string(message.get_member()) == "PropertiesChanged")
929 {
930 std::string interfaceName;
931 dbusPropertiesList propertiesChanged;
932
933 message.read(interfaceName, propertiesChanged);
934
935 powerRestore->setProperties(propertiesChanged);
936 }
937 return 1;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700938}
939
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300940void PowerRestoreController::run()
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700941{
Patrick Williams48aa1f02023-05-10 07:50:30 -0500942 std::string powerRestorePolicyObject = "/xyz/openbmc_project/control/host" +
943 node + "/power_restore_policy";
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300944 powerRestorePolicyLog();
945 // this list only needs to be created once
946 if (matches.empty())
947 {
948 matches.emplace_back(
949 *conn,
950 match_rules::interfacesAdded() +
951 match_rules::argNpath(0, powerRestorePolicyObject) +
952 match_rules::sender(setingsService),
953 powerRestoreConfigHandler, this);
954#ifdef USE_ACBOOT
955 matches.emplace_back(*conn,
956 match_rules::interfacesAdded() +
957 match_rules::argNpath(0, powerACBootObject) +
958 match_rules::sender(setingsService),
959 powerRestoreConfigHandler, this);
960 matches.emplace_back(*conn,
961 match_rules::propertiesChanged(powerACBootObject,
962 powerACBootIface) +
963 match_rules::sender(setingsService),
964 powerRestoreConfigHandler, this);
965#endif // USE_ACBOOT
966 }
967
968 // Check if it's already on DBus
969 conn->async_method_call(
970 [this](boost::system::error_code ec,
971 const dbusPropertiesList properties) {
Patrick Williams48aa1f02023-05-10 07:50:30 -0500972 if (ec)
973 {
974 return;
975 }
976 setProperties(properties);
Patrick Williamsd394c882023-10-20 11:18:44 -0500977 },
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300978 setingsService, powerRestorePolicyObject,
979 "org.freedesktop.DBus.Properties", "GetAll", powerRestorePolicyIface);
980
981#ifdef USE_ACBOOT
982 // Check if it's already on DBus
983 conn->async_method_call(
984 [this](boost::system::error_code ec,
985 const dbusPropertiesList properties) {
Patrick Williams48aa1f02023-05-10 07:50:30 -0500986 if (ec)
987 {
988 return;
989 }
990 setProperties(properties);
Patrick Williamsd394c882023-10-20 11:18:44 -0500991 },
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300992 setingsService, powerACBootObject, "org.freedesktop.DBus.Properties",
993 "GetAll", powerACBootIface);
994#endif
995}
996
997void PowerRestoreController::setProperties(const dbusPropertiesList& props)
998{
999 for (auto& [property, propValue] : props)
1000 {
1001 if (property == "PowerRestorePolicy")
1002 {
1003 const std::string* value = std::get_if<std::string>(&propValue);
1004 if (value == nullptr)
1005 {
1006 lg2::error("Unable to read Power Restore Policy");
1007 continue;
1008 }
1009 powerRestorePolicy = *value;
1010 }
1011 else if (property == "PowerRestoreDelay")
1012 {
1013 const uint64_t* value = std::get_if<uint64_t>(&propValue);
1014 if (value == nullptr)
1015 {
1016 lg2::error("Unable to read Power Restore Delay");
1017 continue;
1018 }
1019 powerRestoreDelay = *value / 1000000; // usec to sec
1020 }
1021#ifdef USE_ACBOOT
1022 else if (property == "ACBoot")
1023 {
1024 const std::string* value = std::get_if<std::string>(&propValue);
1025 if (value == nullptr)
1026 {
1027 lg2::error("Unable to read AC Boot status");
1028 continue;
1029 }
1030 acBoot = *value;
1031 }
1032#endif // USE_ACBOOT
1033 }
1034 invokeIfReady();
1035}
1036
1037void PowerRestoreController::invokeIfReady()
1038{
1039 if ((powerRestorePolicy.empty()) || (powerRestoreDelay < 0))
1040 {
1041 return;
1042 }
1043#ifdef USE_ACBOOT
1044 if (acBoot.empty() || acBoot == "Unknown")
1045 {
1046 return;
1047 }
1048#endif
1049
1050 matches.clear();
1051 if (!timerFired)
1052 {
1053 // Calculate the delay from now to meet the requested delay
1054 // Subtract the approximate uboot time
1055 static constexpr const int ubootSeconds = 20;
1056 int delay = powerRestoreDelay - ubootSeconds;
1057 // Subtract the time since boot
1058 struct sysinfo info = {};
1059 if (sysinfo(&info) == 0)
1060 {
1061 delay -= info.uptime;
1062 }
1063
1064 if (delay > 0)
1065 {
1066 powerRestoreTimer.expires_after(std::chrono::seconds(delay));
1067 lg2::info("Power Restore delay of {DELAY} seconds started", "DELAY",
1068 delay);
Patrick Williams48aa1f02023-05-10 07:50:30 -05001069 powerRestoreTimer.async_wait(
1070 [this](const boost::system::error_code ec) {
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001071 if (ec)
1072 {
1073 // operation_aborted is expected if timer is canceled before
1074 // completion.
1075 if (ec == boost::asio::error::operation_aborted)
1076 {
1077 return;
1078 }
1079 lg2::error(
1080 "power restore policy async_wait failed: {ERROR_MSG}",
1081 "ERROR_MSG", ec.message());
1082 }
1083 else
1084 {
1085 lg2::info("Power Restore delay timer expired");
1086 }
1087 invoke();
1088 });
1089 timerFired = true;
1090 }
1091 else
1092 {
1093 invoke();
1094 }
1095 }
1096}
1097
1098void PowerRestoreController::invoke()
1099{
1100 // we want to run Power Restore only once
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001101 if (policyInvoked)
1102 {
1103 return;
1104 }
1105 policyInvoked = true;
1106
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001107 lg2::info("Invoking Power Restore Policy {POLICY}", "POLICY",
1108 powerRestorePolicy);
1109 if (powerRestorePolicy ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001110 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
1111 {
1112 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001113 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001114 }
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001115 else if (powerRestorePolicy ==
Jason M. Bills418ce112021-09-08 15:15:05 -07001116 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore")
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001117 {
1118 if (wasPowerDropped())
1119 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001120 lg2::info("Power was dropped, restoring Host On state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001121 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001122 setRestartCauseProperty(
1123 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001124 }
1125 else
1126 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001127 lg2::info("No power drop, restoring Host Off state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001128 }
1129 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -07001130 // We're done with the previous power state for the restore policy, so store
1131 // the current state
1132 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001133}
1134
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001135bool PowerRestoreController::wasPowerDropped()
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001136{
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001137 std::string state = appState.get(PersistentState::Params::PowerState);
1138 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001139}
1140
Zev Weiss676ef2c2021-09-02 21:54:02 -05001141static void waitForGPIOEvent(const std::string& name,
1142 const std::function<void(bool)>& eventHandler,
1143 gpiod::line& line,
1144 boost::asio::posix::stream_descriptor& event)
1145{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001146 event.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1147 [&name, eventHandler, &line,
1148 &event](const boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001149 if (ec)
1150 {
1151 lg2::error("{GPIO_NAME} fd handler error: {ERROR_MSG}", "GPIO_NAME",
1152 name, "ERROR_MSG", ec.message());
1153 // TODO: throw here to force power-control to
1154 // restart?
1155 return;
1156 }
1157 gpiod::line_event line_event = line.event_read();
1158 eventHandler(line_event.event_type == gpiod::line_event::RISING_EDGE);
1159 waitForGPIOEvent(name, eventHandler, line, event);
1160 });
Zev Weiss676ef2c2021-09-02 21:54:02 -05001161}
1162
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001163static bool requestGPIOEvents(
Zev Weiss676ef2c2021-09-02 21:54:02 -05001164 const std::string& name, const std::function<void(bool)>& handler,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001165 gpiod::line& gpioLine,
1166 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
1167{
1168 // Find the GPIO line
1169 gpioLine = gpiod::find_line(name);
1170 if (!gpioLine)
1171 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001172 lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001173 return false;
1174 }
1175
1176 try
1177 {
Andrei Kartashev3efcf372021-12-29 15:32:17 +03001178 gpioLine.request({appName, gpiod::line_request::EVENT_BOTH_EDGES, {}});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001179 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001180 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001181 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001182 lg2::error("Failed to request events for {GPIO_NAME}: {ERROR}",
1183 "GPIO_NAME", name, "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001184 return false;
1185 }
1186
1187 int gpioLineFd = gpioLine.event_get_fd();
1188 if (gpioLineFd < 0)
1189 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001190 lg2::error("Failed to get {GPIO_NAME} fd", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001191 return false;
1192 }
1193
1194 gpioEventDescriptor.assign(gpioLineFd);
1195
Zev Weiss676ef2c2021-09-02 21:54:02 -05001196 waitForGPIOEvent(name, handler, gpioLine, gpioEventDescriptor);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001197 return true;
1198}
1199
1200static bool setGPIOOutput(const std::string& name, const int value,
1201 gpiod::line& gpioLine)
1202{
1203 // Find the GPIO line
1204 gpioLine = gpiod::find_line(name);
1205 if (!gpioLine)
1206 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001207 lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001208 return false;
1209 }
1210
1211 // Request GPIO output to specified value
1212 try
1213 {
Andrei Kartashev3efcf372021-12-29 15:32:17 +03001214 gpioLine.request({appName, gpiod::line_request::DIRECTION_OUTPUT, {}},
1215 value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001216 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001217 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001218 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001219 lg2::error("Failed to request {GPIO_NAME} output: {ERROR}", "GPIO_NAME",
1220 name, "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001221 return false;
1222 }
1223
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001224 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1225 "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001226 return true;
1227}
1228
1229static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1230 const std::string& name, const int value,
1231 const int durationMs)
1232{
1233 // Set the masked GPIO line to the specified value
1234 maskedGPIOLine.set_value(value);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001235 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1236 "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001237 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001238 gpioAssertTimer.async_wait(
1239 [maskedGPIOLine, value, name](const boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001240 // Set the masked GPIO line back to the opposite value
1241 maskedGPIOLine.set_value(!value);
1242 lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
1243 if (ec)
1244 {
1245 // operation_aborted is expected if timer is canceled before
1246 // completion.
1247 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001248 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001249 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1250 "GPIO_NAME", name, "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001251 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05001252 }
1253 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001254 return 0;
1255}
1256
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001257static int setGPIOOutputForMs(const ConfigData& config, const int value,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001258 const int durationMs)
1259{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001260 // If the requested GPIO is masked, use the mask line to set the output
1261 if (powerButtonMask && config.lineName == powerOutConfig.lineName)
1262 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001263 return setMaskedGPIOOutputForMs(powerButtonMask, config.lineName, value,
1264 durationMs);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001265 }
1266 if (resetButtonMask && config.lineName == resetOutConfig.lineName)
1267 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001268 return setMaskedGPIOOutputForMs(resetButtonMask, config.lineName, value,
1269 durationMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001270 }
1271
1272 // No mask set, so request and set the GPIO normally
1273 gpiod::line gpioLine;
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001274 if (!setGPIOOutput(config.lineName, value, gpioLine))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001275 {
1276 return -1;
1277 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001278 const std::string name = config.lineName;
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001279
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001280 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001281 gpioAssertTimer.async_wait(
1282 [gpioLine, value, name](const boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001283 // Set the GPIO line back to the opposite value
1284 gpioLine.set_value(!value);
1285 lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
1286 if (ec)
1287 {
1288 // operation_aborted is expected if timer is canceled before
1289 // completion.
1290 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001291 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001292 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1293 "GPIO_NAME", name, "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001294 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05001295 }
1296 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001297 return 0;
1298}
1299
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001300static int assertGPIOForMs(const ConfigData& config, const int durationMs)
1301{
1302 return setGPIOOutputForMs(config, config.polarity, durationMs);
1303}
1304
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001305static void powerOn()
1306{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001307 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001308}
Naveen Moses117c34e2021-05-26 20:10:51 +05301309#ifdef CHASSIS_SYSTEM_RESET
1310static int slotPowerOn()
1311{
1312 if (power_control::slotPowerState != power_control::SlotPowerState::on)
1313 {
Naveen Moses117c34e2021-05-26 20:10:51 +05301314 slotPowerLine.set_value(1);
1315
1316 if (slotPowerLine.get_value() > 0)
1317 {
1318 setSlotPowerState(SlotPowerState::on);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001319 lg2::info("Slot Power is switched On\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301320 }
1321 else
1322 {
1323 return -1;
1324 }
1325 }
1326 else
1327 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001328 lg2::info("Slot Power is already in 'On' state\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301329 return -1;
1330 }
1331 return 0;
1332}
1333static int slotPowerOff()
1334{
1335 if (power_control::slotPowerState != power_control::SlotPowerState::off)
1336 {
1337 slotPowerLine.set_value(0);
1338
1339 if (!(slotPowerLine.get_value() > 0))
1340 {
1341 setSlotPowerState(SlotPowerState::off);
1342 setPowerState(PowerState::off);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001343 lg2::info("Slot Power is switched Off\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301344 }
1345 else
1346 {
1347 return -1;
1348 }
1349 }
1350 else
1351 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001352 lg2::info("Slot Power is already in 'Off' state\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301353 return -1;
1354 }
1355 return 0;
1356}
1357static void slotPowerCycle()
1358{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001359 lg2::info("Slot Power Cycle started\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301360 slotPowerOff();
1361 slotPowerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001362 std::chrono::milliseconds(TimerMap["SlotPowerCycleMs"]));
Naveen Moses117c34e2021-05-26 20:10:51 +05301363 slotPowerCycleTimer.async_wait([](const boost::system::error_code ec) {
1364 if (ec)
1365 {
1366 if (ec != boost::asio::error::operation_aborted)
1367 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001368 lg2::error(
1369 "Slot Power cycle timer async_wait failed: {ERROR_MSG}",
1370 "ERROR_MSG", ec.message());
Naveen Moses117c34e2021-05-26 20:10:51 +05301371 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001372 lg2::info("Slot Power cycle timer canceled\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301373 return;
1374 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001375 lg2::info("Slot Power cycle timer completed\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301376 slotPowerOn();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001377 lg2::info("Slot Power Cycle Completed\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301378 });
1379}
1380#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001381static void gracefulPowerOff()
1382{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001383 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001384}
1385
1386static void forcePowerOff()
1387{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001388 if (assertGPIOForMs(powerOutConfig, TimerMap["ForceOffPulseMs"]) < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001389 {
1390 return;
1391 }
1392
Jason M. Billsc6961b62021-10-21 14:08:02 -07001393 // If the force off timer expires, then the power-button override failed
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001394 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1395 if (ec)
1396 {
1397 // operation_aborted is expected if timer is canceled before
1398 // completion.
1399 if (ec != boost::asio::error::operation_aborted)
1400 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001401 lg2::error("Force power off async_wait failed: {ERROR_MSG}",
1402 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001403 }
1404 return;
1405 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001406
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001407 lg2::error("Power-button override failed. Not sure what to do now.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001408 });
1409}
1410
1411static void reset()
1412{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001413 assertGPIOForMs(resetOutConfig, TimerMap["ResetPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001414}
1415
1416static void gracefulPowerOffTimerStart()
1417{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001418 lg2::info("Graceful power-off timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001419 gracefulPowerOffTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001420 std::chrono::seconds(TimerMap["GracefulPowerOffS"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001421 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1422 if (ec)
1423 {
1424 // operation_aborted is expected if timer is canceled before
1425 // completion.
1426 if (ec != boost::asio::error::operation_aborted)
1427 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001428 lg2::error("Graceful power-off async_wait failed: {ERROR_MSG}",
1429 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001430 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001431 lg2::info("Graceful power-off timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001432 return;
1433 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001434 lg2::info("Graceful power-off timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001435 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1436 });
1437}
1438
1439static void powerCycleTimerStart()
1440{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001441 lg2::info("Power-cycle timer started");
Priyatharshan P70120512020-09-16 18:47:20 +05301442 powerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001443 std::chrono::milliseconds(TimerMap["PowerCycleMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001444 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1445 if (ec)
1446 {
1447 // operation_aborted is expected if timer is canceled before
1448 // completion.
1449 if (ec != boost::asio::error::operation_aborted)
1450 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001451 lg2::error("Power-cycle async_wait failed: {ERROR_MSG}",
1452 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001453 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001454 lg2::info("Power-cycle timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001455 return;
1456 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001457 lg2::info("Power-cycle timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001458 sendPowerControlEvent(Event::powerCycleTimerExpired);
1459 });
1460}
1461
1462static void psPowerOKWatchdogTimerStart()
1463{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001464 lg2::info("power supply power OK watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001465 psPowerOKWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001466 std::chrono::milliseconds(TimerMap["PsPowerOKWatchdogMs"]));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001467 psPowerOKWatchdogTimer.async_wait([](const boost::system::error_code ec) {
1468 if (ec)
1469 {
1470 // operation_aborted is expected if timer is canceled before
1471 // completion.
1472 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001473 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001474 lg2::error(
1475 "power supply power OK watchdog async_wait failed: {ERROR_MSG}",
1476 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001477 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001478 lg2::info("power supply power OK watchdog timer canceled");
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001479 return;
1480 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001481 lg2::info("power supply power OK watchdog timer expired");
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001482 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1483 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001484}
1485
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001486static void warmResetCheckTimerStart()
1487{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001488 lg2::info("Warm reset check timer started");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001489 warmResetCheckTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001490 std::chrono::milliseconds(TimerMap["WarmResetCheckMs"]));
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001491 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1492 if (ec)
1493 {
1494 // operation_aborted is expected if timer is canceled before
1495 // completion.
1496 if (ec != boost::asio::error::operation_aborted)
1497 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001498 lg2::error("Warm reset check async_wait failed: {ERROR_MSG}",
1499 "ERROR_MSG", ec.message());
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001500 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001501 lg2::info("Warm reset check timer canceled");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001502 return;
1503 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001504 lg2::info("Warm reset check timer completed");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001505 sendPowerControlEvent(Event::warmResetDetected);
1506 });
1507}
1508
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001509static void pohCounterTimerStart()
1510{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001511 lg2::info("POH timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001512 // Set the time-out as 1 hour, to align with POH command in ipmid
1513 pohCounterTimer.expires_after(std::chrono::hours(1));
1514 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1515 if (ec)
1516 {
1517 // operation_aborted is expected if timer is canceled before
1518 // completion.
1519 if (ec != boost::asio::error::operation_aborted)
1520 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001521 lg2::error("POH timer async_wait failed: {ERROR_MSG}",
1522 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001523 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001524 lg2::info("POH timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001525 return;
1526 }
1527
1528 if (getHostState(powerState) !=
1529 "xyz.openbmc_project.State.Host.HostState.Running")
1530 {
1531 return;
1532 }
1533
1534 conn->async_method_call(
1535 [](boost::system::error_code ec,
1536 const std::variant<uint32_t>& pohCounterProperty) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001537 if (ec)
1538 {
1539 lg2::error("error getting poh counter");
1540 return;
1541 }
1542 const uint32_t* pohCounter =
1543 std::get_if<uint32_t>(&pohCounterProperty);
1544 if (pohCounter == nullptr)
1545 {
1546 lg2::error("unable to read poh counter");
1547 return;
1548 }
1549
1550 conn->async_method_call(
1551 [](boost::system::error_code ec) {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001552 if (ec)
1553 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05001554 lg2::error("failed to set poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001555 }
Patrick Williamsd394c882023-10-20 11:18:44 -05001556 },
Patrick Williams48aa1f02023-05-10 07:50:30 -05001557 "xyz.openbmc_project.Settings",
1558 "/xyz/openbmc_project/state/chassis0",
1559 "org.freedesktop.DBus.Properties", "Set",
1560 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1561 std::variant<uint32_t>(*pohCounter + 1));
Patrick Williamsd394c882023-10-20 11:18:44 -05001562 },
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001563 "xyz.openbmc_project.Settings",
1564 "/xyz/openbmc_project/state/chassis0",
1565 "org.freedesktop.DBus.Properties", "Get",
1566 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1567
1568 pohCounterTimerStart();
1569 });
1570}
1571
1572static void currentHostStateMonitor()
1573{
Yong Li8d660212019-12-27 10:18:10 +08001574 if (getHostState(powerState) ==
1575 "xyz.openbmc_project.State.Host.HostState.Running")
1576 {
1577 pohCounterTimerStart();
1578 // Clear the restart cause set for the next restart
1579 clearRestartCause();
1580 }
1581 else
1582 {
1583 pohCounterTimer.cancel();
1584 // Set the restart cause set for this restart
1585 setRestartCause();
1586 }
1587
Patrick Williams48aa1f02023-05-10 07:50:30 -05001588 static auto match =
1589 sdbusplus::bus::match_t(*conn,
1590 "type='signal',member='PropertiesChanged', "
1591 "interface='org.freedesktop.DBus.Properties', "
1592 "arg0='xyz.openbmc_project.State.Host'",
1593 [](sdbusplus::message_t& message) {
1594 std::string intfName;
1595 std::map<std::string, std::variant<std::string>> properties;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001596
Patrick Williams48aa1f02023-05-10 07:50:30 -05001597 try
1598 {
1599 message.read(intfName, properties);
1600 }
1601 catch (const std::exception& e)
1602 {
1603 lg2::error("Unable to read host state: {ERROR}", "ERROR", e);
1604 return;
1605 }
1606 if (properties.empty())
1607 {
1608 lg2::error("ERROR: Empty PropertiesChanged signal received");
1609 return;
1610 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001611
Patrick Williams48aa1f02023-05-10 07:50:30 -05001612 // We only want to check for CurrentHostState
1613 if (properties.begin()->first != "CurrentHostState")
1614 {
1615 return;
1616 }
1617 std::string* currentHostState =
1618 std::get_if<std::string>(&(properties.begin()->second));
1619 if (currentHostState == nullptr)
1620 {
1621 lg2::error("{PROPERTY} property invalid", "PROPERTY",
1622 properties.begin()->first);
1623 return;
1624 }
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001625
Patrick Williams48aa1f02023-05-10 07:50:30 -05001626 if (*currentHostState ==
1627 "xyz.openbmc_project.State.Host.HostState.Running")
1628 {
1629 pohCounterTimerStart();
1630 // Clear the restart cause set for the next restart
1631 clearRestartCause();
1632 sd_journal_send("MESSAGE=Host system DC power is on", "PRIORITY=%i",
1633 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
1634 "OpenBMC.0.1.DCPowerOn", NULL);
1635 }
1636 else
1637 {
1638 pohCounterTimer.cancel();
1639 // POST_COMPLETE GPIO event is not working in some platforms
1640 // when power state is changed to OFF. This resulted in
1641 // 'OperatingSystemState' to stay at 'Standby', even though
1642 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1643 // if HostState is trurned to OFF.
1644 setOperatingSystemState(OperatingSystemStateStage::Inactive);
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301645
Patrick Williams48aa1f02023-05-10 07:50:30 -05001646 // Set the restart cause set for this restart
1647 setRestartCause();
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001648#ifdef USE_ACBOOT
Patrick Williams48aa1f02023-05-10 07:50:30 -05001649 resetACBootProperty();
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001650#endif // USE_ACBOOT
Patrick Williams48aa1f02023-05-10 07:50:30 -05001651 sd_journal_send("MESSAGE=Host system DC power is off",
1652 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
1653 "OpenBMC.0.1.DCPowerOff", NULL);
1654 }
Patrick Williamsd394c882023-10-20 11:18:44 -05001655 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001656}
1657
1658static void sioPowerGoodWatchdogTimerStart()
1659{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001660 lg2::info("SIO power good watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001661 sioPowerGoodWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001662 std::chrono::milliseconds(TimerMap["SioPowerGoodWatchdogMs"]));
Patrick Williams48aa1f02023-05-10 07:50:30 -05001663 sioPowerGoodWatchdogTimer.async_wait(
1664 [](const boost::system::error_code ec) {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001665 if (ec)
1666 {
1667 // operation_aborted is expected if timer is canceled before
1668 // completion.
1669 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001670 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001671 lg2::error(
1672 "SIO power good watchdog async_wait failed: {ERROR_MSG}",
1673 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001674 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001675 lg2::info("SIO power good watchdog timer canceled");
1676 return;
1677 }
1678 lg2::info("SIO power good watchdog timer completed");
1679 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1680 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001681}
1682
1683static void powerStateOn(const Event event)
1684{
1685 logEvent(__FUNCTION__, event);
1686 switch (event)
1687 {
1688 case Event::psPowerOKDeAssert:
1689 setPowerState(PowerState::off);
1690 // DC power is unexpectedly lost, beep
1691 beep(beepPowerFail);
1692 break;
1693 case Event::sioS5Assert:
1694 setPowerState(PowerState::transitionToOff);
Matt Simmering58e379d2022-09-23 14:45:50 -07001695#if IGNORE_SOFT_RESETS_DURING_POST
1696 // Only recognize soft resets once host gets past POST COMPLETE
1697 if (operatingSystemState != OperatingSystemStateStage::Standby)
1698 {
1699 ignoreNextSoftReset = true;
1700 }
1701#endif
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001702 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001703 break;
Jason M. Billsfb957332021-01-28 13:18:46 -08001704#if USE_PLT_RST
1705 case Event::pltRstAssert:
1706#else
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001707 case Event::postCompleteDeAssert:
Jason M. Billsfb957332021-01-28 13:18:46 -08001708#endif
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001709 setPowerState(PowerState::checkForWarmReset);
Matt Simmering58e379d2022-09-23 14:45:50 -07001710#if IGNORE_SOFT_RESETS_DURING_POST
1711 // Only recognize soft resets once host gets past POST COMPLETE
1712 if (operatingSystemState != OperatingSystemStateStage::Standby)
1713 {
1714 ignoreNextSoftReset = true;
1715 }
1716#endif
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001717 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001718 warmResetCheckTimerStart();
1719 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001720 case Event::powerButtonPressed:
1721 setPowerState(PowerState::gracefulTransitionToOff);
1722 gracefulPowerOffTimerStart();
1723 break;
1724 case Event::powerOffRequest:
1725 setPowerState(PowerState::transitionToOff);
1726 forcePowerOff();
1727 break;
1728 case Event::gracefulPowerOffRequest:
1729 setPowerState(PowerState::gracefulTransitionToOff);
1730 gracefulPowerOffTimerStart();
1731 gracefulPowerOff();
1732 break;
1733 case Event::powerCycleRequest:
1734 setPowerState(PowerState::transitionToCycleOff);
1735 forcePowerOff();
1736 break;
1737 case Event::gracefulPowerCycleRequest:
1738 setPowerState(PowerState::gracefulTransitionToCycleOff);
1739 gracefulPowerOffTimerStart();
1740 gracefulPowerOff();
1741 break;
Jayanth Othayothdc0bab92024-02-07 07:24:35 -06001742 case Event::resetButtonPressed:
1743 setPowerState(PowerState::checkForWarmReset);
1744 warmResetCheckTimerStart();
1745 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001746 case Event::resetRequest:
1747 reset();
1748 break;
1749 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001750 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001751 break;
1752 }
1753}
1754
1755static void powerStateWaitForPSPowerOK(const Event event)
1756{
1757 logEvent(__FUNCTION__, event);
1758 switch (event)
1759 {
1760 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301761 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001762 // Cancel any GPIO assertions held during the transition
1763 gpioAssertTimer.cancel();
1764 psPowerOKWatchdogTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301765 if (sioEnabled == true)
1766 {
1767 sioPowerGoodWatchdogTimerStart();
1768 setPowerState(PowerState::waitForSIOPowerGood);
1769 }
1770 else
1771 {
1772 setPowerState(PowerState::on);
1773 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001774 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301775 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001776 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001777 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001778 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001779 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001780 case Event::sioPowerGoodAssert:
1781 psPowerOKWatchdogTimer.cancel();
1782 setPowerState(PowerState::on);
1783 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001784 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001785 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001786 break;
1787 }
1788}
1789
1790static void powerStateWaitForSIOPowerGood(const Event event)
1791{
1792 logEvent(__FUNCTION__, event);
1793 switch (event)
1794 {
1795 case Event::sioPowerGoodAssert:
1796 sioPowerGoodWatchdogTimer.cancel();
1797 setPowerState(PowerState::on);
1798 break;
1799 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001800 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001801 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001802 break;
1803 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001804 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001805 break;
1806 }
1807}
1808
1809static void powerStateOff(const Event event)
1810{
1811 logEvent(__FUNCTION__, event);
1812 switch (event)
1813 {
1814 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301815 {
1816 if (sioEnabled == true)
1817 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001818 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301819 setPowerState(PowerState::waitForSIOPowerGood);
1820 }
1821 else
1822 {
1823 setPowerState(PowerState::on);
1824 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001825 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301826 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001827 case Event::sioS5DeAssert:
Jason M. Billsfe159032022-09-01 16:03:37 -07001828 psPowerOKWatchdogTimerStart();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001829 setPowerState(PowerState::waitForPSPowerOK);
1830 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001831 case Event::sioPowerGoodAssert:
1832 setPowerState(PowerState::on);
1833 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001834 case Event::powerButtonPressed:
1835 psPowerOKWatchdogTimerStart();
1836 setPowerState(PowerState::waitForPSPowerOK);
1837 break;
1838 case Event::powerOnRequest:
1839 psPowerOKWatchdogTimerStart();
1840 setPowerState(PowerState::waitForPSPowerOK);
1841 powerOn();
1842 break;
1843 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001844 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001845 break;
1846 }
1847}
1848
1849static void powerStateTransitionToOff(const Event event)
1850{
1851 logEvent(__FUNCTION__, event);
1852 switch (event)
1853 {
1854 case Event::psPowerOKDeAssert:
1855 // Cancel any GPIO assertions held during the transition
1856 gpioAssertTimer.cancel();
1857 setPowerState(PowerState::off);
1858 break;
1859 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001860 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001861 break;
1862 }
1863}
1864
1865static void powerStateGracefulTransitionToOff(const Event event)
1866{
1867 logEvent(__FUNCTION__, event);
1868 switch (event)
1869 {
1870 case Event::psPowerOKDeAssert:
1871 gracefulPowerOffTimer.cancel();
1872 setPowerState(PowerState::off);
1873 break;
1874 case Event::gracefulPowerOffTimerExpired:
1875 setPowerState(PowerState::on);
1876 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001877 case Event::powerOffRequest:
1878 gracefulPowerOffTimer.cancel();
1879 setPowerState(PowerState::transitionToOff);
1880 forcePowerOff();
1881 break;
1882 case Event::powerCycleRequest:
1883 gracefulPowerOffTimer.cancel();
1884 setPowerState(PowerState::transitionToCycleOff);
1885 forcePowerOff();
1886 break;
1887 case Event::resetRequest:
1888 gracefulPowerOffTimer.cancel();
1889 setPowerState(PowerState::on);
1890 reset();
1891 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001892 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001893 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001894 break;
1895 }
1896}
1897
1898static void powerStateCycleOff(const Event event)
1899{
1900 logEvent(__FUNCTION__, event);
1901 switch (event)
1902 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001903 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301904 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001905 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301906 if (sioEnabled == true)
1907 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001908 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301909 setPowerState(PowerState::waitForSIOPowerGood);
1910 }
1911 else
1912 {
1913 setPowerState(PowerState::on);
1914 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001915 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301916 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001917 case Event::sioS5DeAssert:
1918 powerCycleTimer.cancel();
Jason M. Billsfe159032022-09-01 16:03:37 -07001919 psPowerOKWatchdogTimerStart();
Jason M. Bills35aa6652020-04-30 16:24:55 -07001920 setPowerState(PowerState::waitForPSPowerOK);
1921 break;
1922 case Event::powerButtonPressed:
1923 powerCycleTimer.cancel();
1924 psPowerOKWatchdogTimerStart();
1925 setPowerState(PowerState::waitForPSPowerOK);
1926 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001927 case Event::powerCycleTimerExpired:
1928 psPowerOKWatchdogTimerStart();
1929 setPowerState(PowerState::waitForPSPowerOK);
1930 powerOn();
1931 break;
1932 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001933 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001934 break;
1935 }
1936}
1937
1938static void powerStateTransitionToCycleOff(const Event event)
1939{
1940 logEvent(__FUNCTION__, event);
1941 switch (event)
1942 {
1943 case Event::psPowerOKDeAssert:
1944 // Cancel any GPIO assertions held during the transition
1945 gpioAssertTimer.cancel();
1946 setPowerState(PowerState::cycleOff);
1947 powerCycleTimerStart();
1948 break;
1949 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001950 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001951 break;
1952 }
1953}
1954
1955static void powerStateGracefulTransitionToCycleOff(const Event event)
1956{
1957 logEvent(__FUNCTION__, event);
1958 switch (event)
1959 {
1960 case Event::psPowerOKDeAssert:
1961 gracefulPowerOffTimer.cancel();
1962 setPowerState(PowerState::cycleOff);
1963 powerCycleTimerStart();
1964 break;
1965 case Event::gracefulPowerOffTimerExpired:
1966 setPowerState(PowerState::on);
1967 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001968 case Event::powerOffRequest:
1969 gracefulPowerOffTimer.cancel();
1970 setPowerState(PowerState::transitionToOff);
1971 forcePowerOff();
1972 break;
1973 case Event::powerCycleRequest:
1974 gracefulPowerOffTimer.cancel();
1975 setPowerState(PowerState::transitionToCycleOff);
1976 forcePowerOff();
1977 break;
1978 case Event::resetRequest:
1979 gracefulPowerOffTimer.cancel();
1980 setPowerState(PowerState::on);
1981 reset();
1982 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001983 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001984 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001985 break;
1986 }
1987}
1988
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001989static void powerStateCheckForWarmReset(const Event event)
1990{
1991 logEvent(__FUNCTION__, event);
1992 switch (event)
1993 {
1994 case Event::sioS5Assert:
1995 warmResetCheckTimer.cancel();
1996 setPowerState(PowerState::transitionToOff);
1997 break;
1998 case Event::warmResetDetected:
1999 setPowerState(PowerState::on);
2000 break;
P.K. Lee344dae82019-11-27 16:35:05 +08002001 case Event::psPowerOKDeAssert:
2002 warmResetCheckTimer.cancel();
2003 setPowerState(PowerState::off);
2004 // DC power is unexpectedly lost, beep
2005 beep(beepPowerFail);
2006 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002007 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002008 lg2::info("No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002009 break;
2010 }
2011}
2012
Zev Weiss584aa132021-09-02 19:21:52 -05002013static void psPowerOKHandler(bool state)
2014{
Patrick Williams48aa1f02023-05-10 07:50:30 -05002015 Event powerControlEvent = state ? Event::psPowerOKAssert
2016 : Event::psPowerOKDeAssert;
Zev Weiss584aa132021-09-02 19:21:52 -05002017 sendPowerControlEvent(powerControlEvent);
2018}
2019
Zev Weiss584aa132021-09-02 19:21:52 -05002020static void sioPowerGoodHandler(bool state)
2021{
Patrick Williams48aa1f02023-05-10 07:50:30 -05002022 Event powerControlEvent = state ? Event::sioPowerGoodAssert
2023 : Event::sioPowerGoodDeAssert;
Zev Weiss584aa132021-09-02 19:21:52 -05002024 sendPowerControlEvent(powerControlEvent);
2025}
2026
Zev Weiss584aa132021-09-02 19:21:52 -05002027static void sioOnControlHandler(bool state)
2028{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002029 lg2::info("SIO_ONCONTROL value changed: {VALUE}", "VALUE",
2030 static_cast<int>(state));
Zev Weiss584aa132021-09-02 19:21:52 -05002031}
2032
Zev Weiss584aa132021-09-02 19:21:52 -05002033static void sioS5Handler(bool state)
2034{
2035 Event powerControlEvent = state ? Event::sioS5DeAssert : Event::sioS5Assert;
2036 sendPowerControlEvent(powerControlEvent);
2037}
2038
Zev Weiss584aa132021-09-02 19:21:52 -05002039static void powerButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002040{
Zev Weiss584aa132021-09-02 19:21:52 -05002041 powerButtonIface->set_property("ButtonPressed", !state);
2042 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002043 {
2044 powerButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002045 if (!powerButtonMask)
2046 {
2047 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002048 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002049 }
2050 else
2051 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002052 lg2::info("power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002053 }
2054 }
Zev Weiss584aa132021-09-02 19:21:52 -05002055}
2056
Zev Weiss584aa132021-09-02 19:21:52 -05002057static void resetButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002058{
Zev Weiss584aa132021-09-02 19:21:52 -05002059 resetButtonIface->set_property("ButtonPressed", !state);
2060 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002061 {
2062 resetButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002063 if (!resetButtonMask)
2064 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002065 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002066 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002067 }
2068 else
2069 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002070 lg2::info("reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002071 }
2072 }
Zev Weiss584aa132021-09-02 19:21:52 -05002073}
2074
Vijay Khemka04175c22020-10-09 14:28:11 -07002075#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002076static constexpr auto systemdBusname = "org.freedesktop.systemd1";
2077static constexpr auto systemdPath = "/org/freedesktop/systemd1";
2078static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
2079static constexpr auto systemTargetName = "chassis-system-reset.target";
2080
2081void systemReset()
2082{
2083 conn->async_method_call(
2084 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002085 if (ec)
2086 {
2087 lg2::error("Failed to call chassis system reset: {ERR}", "ERR",
2088 ec.message());
2089 }
Patrick Williamsd394c882023-10-20 11:18:44 -05002090 },
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002091 systemdBusname, systemdPath, systemdInterface, "StartUnit",
2092 systemTargetName, "replace");
2093}
Vijay Khemka04175c22020-10-09 14:28:11 -07002094#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002095
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002096static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002097{
2098 conn->async_method_call(
2099 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002100 if (ec)
2101 {
2102 lg2::error("failed to set NMI source");
2103 }
Patrick Williamsd394c882023-10-20 11:18:44 -05002104 },
Chen Yugang303bd582019-11-01 08:45:06 +08002105 "xyz.openbmc_project.Settings",
2106 "/xyz/openbmc_project/Chassis/Control/NMISource",
2107 "org.freedesktop.DBus.Properties", "Set",
2108 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
2109 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002110}
2111
2112static void nmiReset(void)
2113{
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002114 const static constexpr int nmiOutPulseTimeMs = 200;
2115
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002116 lg2::info("NMI out action");
Jian Zhang461a1662022-09-22 11:29:01 +08002117 nmiOutLine.set_value(nmiOutConfig.polarity);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002118 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME",
Jian Zhang461a1662022-09-22 11:29:01 +08002119 nmiOutConfig.lineName, "GPIO_VALUE", nmiOutConfig.polarity);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002120 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2121 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2122 // restore the NMI_OUT GPIO line back to the opposite value
Jian Zhang461a1662022-09-22 11:29:01 +08002123 nmiOutLine.set_value(!nmiOutConfig.polarity);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002124 lg2::info("{GPIO_NAME} released", "GPIO_NAME", nmiOutConfig.lineName);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002125 if (ec)
2126 {
2127 // operation_aborted is expected if timer is canceled before
2128 // completion.
2129 if (ec != boost::asio::error::operation_aborted)
2130 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002131 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
2132 "GPIO_NAME", nmiOutConfig.lineName, "ERROR_MSG",
2133 ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002134 }
2135 }
2136 });
2137 // log to redfish
2138 nmiDiagIntLog();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002139 lg2::info("NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002140 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002141 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002142}
2143
2144static void nmiSourcePropertyMonitor(void)
2145{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002146 lg2::info("NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002147
Patrick Williams439b9c32022-07-22 19:26:53 -05002148 static std::unique_ptr<sdbusplus::bus::match_t> nmiSourceMatch =
2149 std::make_unique<sdbusplus::bus::match_t>(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002150 *conn,
2151 "type='signal',interface='org.freedesktop.DBus.Properties',"
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002152 "member='PropertiesChanged',"
2153 "arg0namespace='xyz.openbmc_project.Chassis.Control.NMISource'",
Patrick Williams439b9c32022-07-22 19:26:53 -05002154 [](sdbusplus::message_t& msg) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002155 std::string interfaceName;
2156 boost::container::flat_map<std::string, std::variant<bool, std::string>>
2157 propertiesChanged;
2158 std::string state;
2159 bool value = true;
2160 try
2161 {
2162 msg.read(interfaceName, propertiesChanged);
2163 if (propertiesChanged.begin()->first == "Enabled")
2164 {
2165 value = std::get<bool>(propertiesChanged.begin()->second);
2166 lg2::info("NMI Enabled propertiesChanged value: {VALUE}",
2167 "VALUE", value);
2168 nmiEnabled = value;
2169 if (nmiEnabled)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002170 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002171 nmiReset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002172 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05002173 }
2174 }
2175 catch (const std::exception& e)
2176 {
2177 lg2::error("Unable to read NMI source: {ERROR}", "ERROR", e);
2178 return;
2179 }
Patrick Williamsd394c882023-10-20 11:18:44 -05002180 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002181}
2182
2183static void setNmiSource()
2184{
2185 conn->async_method_call(
2186 [](boost::system::error_code ec) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002187 if (ec)
2188 {
2189 lg2::error("failed to set NMI source");
2190 }
Patrick Williamsd394c882023-10-20 11:18:44 -05002191 },
Chen Yugang303bd582019-11-01 08:45:06 +08002192 "xyz.openbmc_project.Settings",
2193 "/xyz/openbmc_project/Chassis/Control/NMISource",
2194 "org.freedesktop.DBus.Properties", "Set",
2195 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
Jason M. Bills418ce112021-09-08 15:15:05 -07002196 std::variant<std::string>{
2197 "xyz.openbmc_project.Chassis.Control.NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002198 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002199 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002200}
2201
Zev Weiss584aa132021-09-02 19:21:52 -05002202static void nmiButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002203{
Olivier FAURAXd7ea2832023-04-14 14:08:02 +00002204 // Don't handle event if host not running and config doesn't force it
2205 if (!nmiWhenPoweredOff &&
2206 getHostState(powerState) !=
2207 "xyz.openbmc_project.State.Host.HostState.Running")
2208 {
2209 return;
2210 }
Zev Weiss584aa132021-09-02 19:21:52 -05002211 nmiButtonIface->set_property("ButtonPressed", !state);
2212 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002213 {
2214 nmiButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002215 if (nmiButtonMasked)
2216 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002217 lg2::info("NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002218 }
2219 else
2220 {
2221 setNmiSource();
2222 }
2223 }
Zev Weiss584aa132021-09-02 19:21:52 -05002224}
2225
Zev Weiss584aa132021-09-02 19:21:52 -05002226static void idButtonHandler(bool state)
2227{
2228 idButtonIface->set_property("ButtonPressed", !state);
2229}
2230
Jason M. Billsfb957332021-01-28 13:18:46 -08002231static void pltRstHandler(bool pltRst)
2232{
2233 if (pltRst)
2234 {
2235 sendPowerControlEvent(Event::pltRstDeAssert);
2236 }
2237 else
2238 {
2239 sendPowerControlEvent(Event::pltRstAssert);
2240 }
2241}
2242
Patrick Williams439b9c32022-07-22 19:26:53 -05002243[[maybe_unused]] static void hostMiscHandler(sdbusplus::message_t& msg)
Jason M. Billsfb957332021-01-28 13:18:46 -08002244{
2245 std::string interfaceName;
2246 boost::container::flat_map<std::string, std::variant<bool>>
2247 propertiesChanged;
Jason M. Billsfb957332021-01-28 13:18:46 -08002248 try
2249 {
2250 msg.read(interfaceName, propertiesChanged);
2251 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002252 catch (const std::exception& e)
Jason M. Billsfb957332021-01-28 13:18:46 -08002253 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002254 lg2::error("Unable to read Host Misc status: {ERROR}", "ERROR", e);
Jason M. Billsfb957332021-01-28 13:18:46 -08002255 return;
2256 }
2257 if (propertiesChanged.empty())
2258 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002259 lg2::error("ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002260 return;
2261 }
2262
2263 for (auto& [property, value] : propertiesChanged)
2264 {
2265 if (property == "ESpiPlatformReset")
2266 {
2267 bool* pltRst = std::get_if<bool>(&value);
2268 if (pltRst == nullptr)
2269 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002270 lg2::error("{PROPERTY} property invalid", "PROPERTY", property);
Jason M. Billsfb957332021-01-28 13:18:46 -08002271 return;
2272 }
2273 pltRstHandler(*pltRst);
2274 }
2275 }
2276}
2277
Zev Weiss584aa132021-09-02 19:21:52 -05002278static void postCompleteHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002279{
Zev Weiss584aa132021-09-02 19:21:52 -05002280 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002281 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002282 sendPowerControlEvent(Event::postCompleteAssert);
Tim Lee86239182021-12-23 11:46:01 +08002283 setOperatingSystemState(OperatingSystemStateStage::Standby);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002284 }
2285 else
2286 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002287 sendPowerControlEvent(Event::postCompleteDeAssert);
Tim Lee86239182021-12-23 11:46:01 +08002288 setOperatingSystemState(OperatingSystemStateStage::Inactive);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002289 }
Zev Weiss584aa132021-09-02 19:21:52 -05002290}
2291
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302292static int loadConfigValues()
2293{
2294 const std::string configFilePath =
2295 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2296 ".json";
2297 std::ifstream configFile(configFilePath.c_str());
2298 if (!configFile.is_open())
2299 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002300 lg2::error("loadConfigValues: Cannot open config path \'{PATH}\'",
2301 "PATH", configFilePath);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302302 return -1;
2303 }
Zev Weiss1aa08b22021-09-15 17:06:20 -05002304 auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302305
Priyatharshan P70120512020-09-16 18:47:20 +05302306 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302307 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002308 lg2::error("Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302309 return -1;
2310 }
Priyatharshan P70120512020-09-16 18:47:20 +05302311 auto gpios = jsonData["gpio_configs"];
2312 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302313
Priyatharshan P70120512020-09-16 18:47:20 +05302314 ConfigData* tempGpioData;
2315
2316 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302317 {
Priyatharshan P70120512020-09-16 18:47:20 +05302318 if (!gpioConfig.contains("Name"))
2319 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002320 lg2::error("The 'Name' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302321 return -1;
2322 }
2323
2324 // Iterate through the powersignal map to check if the gpio json config
2325 // entry is valid
2326 std::string gpioName = gpioConfig["Name"];
2327 auto signalMapIter = powerSignalMap.find(gpioName);
2328 if (signalMapIter == powerSignalMap.end())
2329 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002330 lg2::error(
2331 "{GPIO_NAME} is not a recognized power-control signal name",
2332 "GPIO_NAME", gpioName);
Priyatharshan P70120512020-09-16 18:47:20 +05302333 return -1;
2334 }
2335
2336 // assign the power signal name to the corresponding structure reference
2337 // from map then fillup the structure with coressponding json config
2338 // value
2339 tempGpioData = signalMapIter->second;
2340 tempGpioData->name = gpioName;
2341
2342 if (!gpioConfig.contains("Type"))
2343 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002344 lg2::error("The \'Type\' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302345 return -1;
2346 }
2347
2348 std::string signalType = gpioConfig["Type"];
2349 if (signalType == "GPIO")
2350 {
2351 tempGpioData->type = ConfigType::GPIO;
2352 }
2353 else if (signalType == "DBUS")
2354 {
2355 tempGpioData->type = ConfigType::DBUS;
2356 }
2357 else
2358 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002359 lg2::error("{TYPE} is not a recognized power-control signal type",
2360 "TYPE", signalType);
Priyatharshan P70120512020-09-16 18:47:20 +05302361 return -1;
2362 }
2363
2364 if (tempGpioData->type == ConfigType::GPIO)
2365 {
2366 if (gpioConfig.contains("LineName"))
2367 {
2368 tempGpioData->lineName = gpioConfig["LineName"];
2369 }
2370 else
2371 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002372 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002373 "The \'LineName\' field must be defined for GPIO configuration");
Priyatharshan P70120512020-09-16 18:47:20 +05302374 return -1;
2375 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002376 if (gpioConfig.contains("Polarity"))
2377 {
2378 std::string polarity = gpioConfig["Polarity"];
2379 if (polarity == "ActiveLow")
2380 {
2381 tempGpioData->polarity = false;
2382 }
2383 else if (polarity == "ActiveHigh")
2384 {
2385 tempGpioData->polarity = true;
2386 }
2387 else
2388 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002389 lg2::error(
2390 "Polarity defined but not properly setup. Please only ActiveHigh or ActiveLow. Currently set to {POLARITY}",
2391 "POLARITY", polarity);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002392 return -1;
2393 }
2394 }
2395 else
2396 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002397 lg2::error("Polarity field not found for {GPIO_NAME}",
2398 "GPIO_NAME", tempGpioData->lineName);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002399 return -1;
2400 }
Priyatharshan P70120512020-09-16 18:47:20 +05302401 }
2402 else
2403 {
2404 // if dbus based gpio config is defined read and update the dbus
2405 // params corresponding to the gpio config instance
2406 for (auto& [key, dbusParamName] : dbusParams)
2407 {
Logananth Sundararaja4308042021-10-20 11:52:05 +05302408 if (!gpioConfig.contains(dbusParamName))
Priyatharshan P70120512020-09-16 18:47:20 +05302409 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002410 lg2::error(
2411 "The {DBUS_NAME} field must be defined for Dbus configuration ",
2412 "DBUS_NAME", dbusParamName);
Priyatharshan P70120512020-09-16 18:47:20 +05302413 return -1;
2414 }
2415 }
Logananth Sundararaja4308042021-10-20 11:52:05 +05302416 tempGpioData->dbusName =
2417 gpioConfig[dbusParams[DbusConfigType::name]];
2418 tempGpioData->path = gpioConfig[dbusParams[DbusConfigType::path]];
Priyatharshan P70120512020-09-16 18:47:20 +05302419 tempGpioData->interface =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302420 gpioConfig[dbusParams[DbusConfigType::interface]];
Priyatharshan P70120512020-09-16 18:47:20 +05302421 tempGpioData->lineName =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302422 gpioConfig[dbusParams[DbusConfigType::property]];
Priyatharshan P70120512020-09-16 18:47:20 +05302423 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302424 }
2425
Priyatharshan P70120512020-09-16 18:47:20 +05302426 // read and store the timer values from json config to Timer Map
2427 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302428 {
Priyatharshan P70120512020-09-16 18:47:20 +05302429 if (timers.contains(key.c_str()))
2430 {
2431 timerValue = timers[key.c_str()];
2432 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302433 }
2434
Jonathan Doman891bbde2023-05-17 13:58:24 -07002435 // If "events_configs" key is not in json config, fallback to null
2436 auto events = jsonData.value("event_configs",
2437 nlohmann::json(nlohmann::json::value_t::null));
2438 if (events.is_object())
Olivier FAURAXd7ea2832023-04-14 14:08:02 +00002439 {
2440 nmiWhenPoweredOff = events.value("NMIWhenPoweredOff", true);
2441 }
2442
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302443 return 0;
2444}
Zev Weissa8f116a2021-09-01 21:08:30 -05002445
Patrick Williams439b9c32022-07-22 19:26:53 -05002446static bool getDbusMsgGPIOState(sdbusplus::message_t& msg,
Zev Weissa8f116a2021-09-01 21:08:30 -05002447 const std::string& lineName, bool& value)
2448{
2449 std::string thresholdInterface;
2450 std::string event;
2451 boost::container::flat_map<std::string, std::variant<bool>>
2452 propertiesChanged;
2453 try
2454 {
2455 msg.read(thresholdInterface, propertiesChanged);
2456 if (propertiesChanged.empty())
2457 {
2458 return false;
2459 }
2460
2461 event = propertiesChanged.begin()->first;
2462 if (event.empty() || event != lineName)
2463 {
2464 return false;
2465 }
2466
2467 value = std::get<bool>(propertiesChanged.begin()->second);
2468 return true;
2469 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002470 catch (const std::exception& e)
Zev Weissa8f116a2021-09-01 21:08:30 -05002471 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002472 lg2::error(
2473 "exception while reading dbus property \'{DBUS_NAME}\': {ERROR}",
2474 "DBUS_NAME", lineName, "ERROR", e);
Zev Weissa8f116a2021-09-01 21:08:30 -05002475 return false;
2476 }
2477}
2478
Patrick Williams439b9c32022-07-22 19:26:53 -05002479static sdbusplus::bus::match_t
Zev Weissa8f116a2021-09-01 21:08:30 -05002480 dbusGPIOMatcher(const ConfigData& cfg, std::function<void(bool)> onMatch)
2481{
Patrick Williamsd394c882023-10-20 11:18:44 -05002482 auto pulseEventMatcherCallback = [&cfg,
2483 onMatch](sdbusplus::message_t& msg) {
Patrick Williams439b9c32022-07-22 19:26:53 -05002484 bool value = false;
2485 if (!getDbusMsgGPIOState(msg, cfg.lineName, value))
2486 {
2487 return;
2488 }
2489 onMatch(value);
2490 };
Zev Weissa8f116a2021-09-01 21:08:30 -05002491
Patrick Williams439b9c32022-07-22 19:26:53 -05002492 return sdbusplus::bus::match_t(
2493 static_cast<sdbusplus::bus_t&>(*conn),
Zev Weissa8f116a2021-09-01 21:08:30 -05002494 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2495 "PropertiesChanged',arg0='" +
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302496 cfg.interface + "'",
Zev Weissa8f116a2021-09-01 21:08:30 -05002497 std::move(pulseEventMatcherCallback));
2498}
2499
Michal Orzeledd211e2022-10-28 13:10:16 +02002500// D-Bus property read functions
2501void reschedulePropertyRead(const ConfigData& configData);
Priyatharshan P70120512020-09-16 18:47:20 +05302502
Michal Orzeledd211e2022-10-28 13:10:16 +02002503int getProperty(const ConfigData& configData)
2504{
2505 std::variant<bool> resp;
2506
2507 try
Priyatharshan P70120512020-09-16 18:47:20 +05302508 {
Michal Orzeledd211e2022-10-28 13:10:16 +02002509 auto method = conn->new_method_call(
2510 configData.dbusName.c_str(), configData.path.c_str(),
2511 "org.freedesktop.DBus.Properties", "Get");
2512 method.append(configData.interface.c_str(),
2513 configData.lineName.c_str());
2514
2515 auto reply = conn->call(method);
2516 if (reply.is_method_error())
2517 {
2518 lg2::error(
2519 "Error reading {PROPERTY} D-Bus property on interface {INTERFACE} and path {PATH}",
2520 "PROPERTY", configData.lineName, "INTERFACE",
2521 configData.interface, "PATH", configData.path);
2522 return -1;
2523 }
2524
2525 reply.read(resp);
2526 }
2527 catch (const sdbusplus::exception_t& e)
2528 {
2529 lg2::error("Exception while reading {PROPERTY}: {WHAT}", "PROPERTY",
2530 configData.lineName, "WHAT", e.what());
2531 reschedulePropertyRead(configData);
Priyatharshan P70120512020-09-16 18:47:20 +05302532 return -1;
2533 }
Michal Orzeledd211e2022-10-28 13:10:16 +02002534
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302535 auto respValue = std::get_if<bool>(&resp);
Priyatharshan P70120512020-09-16 18:47:20 +05302536 if (!respValue)
2537 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002538 lg2::error("Error: {PROPERTY} D-Bus property is not the expected type",
2539 "PROPERTY", configData.lineName);
Priyatharshan P70120512020-09-16 18:47:20 +05302540 return -1;
2541 }
2542 return (*respValue);
2543}
Michal Orzeledd211e2022-10-28 13:10:16 +02002544
2545void setInitialValue(const ConfigData& configData, bool initialValue)
2546{
2547 if (configData.name == "PowerOk")
2548 {
2549 powerState = (initialValue ? PowerState::on : PowerState::off);
2550 hostIface->set_property("CurrentHostState",
2551 std::string(getHostState(powerState)));
2552 }
2553 else if (configData.name == "PowerButton")
2554 {
2555 powerButtonIface->set_property("ButtonPressed", !initialValue);
2556 }
2557 else if (configData.name == "ResetButton")
2558 {
2559 resetButtonIface->set_property("ButtonPressed", !initialValue);
2560 }
2561 else if (configData.name == "NMIButton")
2562 {
2563 nmiButtonIface->set_property("ButtonPressed", !initialValue);
2564 }
2565 else if (configData.name == "IdButton")
2566 {
2567 idButtonIface->set_property("ButtonPressed", !initialValue);
2568 }
2569 else if (configData.name == "PostComplete")
2570 {
2571 OperatingSystemStateStage osState =
2572 (initialValue ? OperatingSystemStateStage::Inactive
2573 : OperatingSystemStateStage::Standby);
2574 setOperatingSystemState(osState);
2575 }
2576 else
2577 {
2578 lg2::error("Unknown name {NAME}", "NAME", configData.name);
2579 }
2580}
2581
2582void reschedulePropertyRead(const ConfigData& configData)
2583{
2584 auto item = dBusRetryTimers.find(configData.name);
2585
2586 if (item == dBusRetryTimers.end())
2587 {
2588 auto newItem = dBusRetryTimers.insert(
2589 {configData.name, boost::asio::steady_timer(io)});
2590
2591 if (!newItem.second)
2592 {
2593 lg2::error("Failed to add new timer for {NAME}", "NAME",
2594 configData.name);
2595 return;
2596 }
2597
2598 item = newItem.first;
2599 }
2600
2601 auto& timer = item->second;
2602 timer.expires_after(
2603 std::chrono::milliseconds(TimerMap["DbusGetPropertyRetry"]));
2604 timer.async_wait([&configData](const boost::system::error_code ec) {
2605 if (ec)
2606 {
2607 lg2::error("Retry timer for {NAME} failed: {MSG}", "NAME",
2608 configData.name, "MSG", ec.message());
2609 dBusRetryTimers.erase(configData.name);
2610 return;
2611 }
2612
2613 int property = getProperty(configData);
2614
2615 if (property >= 0)
2616 {
2617 setInitialValue(configData, (property > 0));
2618 dBusRetryTimers.erase(configData.name);
2619 }
2620 });
2621}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002622} // namespace power_control
2623
2624int main(int argc, char* argv[])
2625{
Lei YU92caa4c2021-02-23 16:59:25 +08002626 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05302627
2628 if (argc > 1)
2629 {
2630 node = argv[1];
2631 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002632 lg2::info("Start Chassis power control service for host : {NODE}", "NODE",
2633 node);
Priyatharshan P70120512020-09-16 18:47:20 +05302634
Lei YU92caa4c2021-02-23 16:59:25 +08002635 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002636
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302637 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08002638 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302639 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002640 lg2::error("Host{NODE}: Error in Parsing...", "NODE", node);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302641 }
Naveen Mosesec972d82021-07-16 21:19:23 +05302642 /* Currently for single host based systems additional busname is added
2643 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
2644 Going forward for single hosts the old bus name without zero numbering
2645 will be removed when all other applications adapted to the
2646 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
2647
2648 if (node == "0")
2649 {
2650 // Request all the dbus names
2651 conn->request_name(hostDbusName.c_str());
2652 conn->request_name(chassisDbusName.c_str());
2653 conn->request_name(osDbusName.c_str());
2654 conn->request_name(buttonDbusName.c_str());
2655 conn->request_name(nmiDbusName.c_str());
2656 conn->request_name(rstCauseDbusName.c_str());
2657 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302658
Zev Weissc4005bd2021-09-01 22:30:23 -05002659 hostDbusName += node;
2660 chassisDbusName += node;
2661 osDbusName += node;
2662 buttonDbusName += node;
2663 nmiDbusName += node;
2664 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002665
Priyatharshan P70120512020-09-16 18:47:20 +05302666 // Request all the dbus names
2667 conn->request_name(hostDbusName.c_str());
2668 conn->request_name(chassisDbusName.c_str());
2669 conn->request_name(osDbusName.c_str());
2670 conn->request_name(buttonDbusName.c_str());
2671 conn->request_name(nmiDbusName.c_str());
2672 conn->request_name(rstCauseDbusName.c_str());
2673
2674 if (sioPwrGoodConfig.lineName.empty() ||
2675 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05302676 {
Lei YU92caa4c2021-02-23 16:59:25 +08002677 sioEnabled = false;
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002678 lg2::info("SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05302679 }
2680
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002681 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302682 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002683 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002684 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302685 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302686 {
2687 return -1;
2688 }
2689 }
Priyatharshan P70120512020-09-16 18:47:20 +05302690 else if (powerOkConfig.type == ConfigType::DBUS)
2691 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002692 static sdbusplus::bus::match_t powerOkEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002693 power_control::dbusGPIOMatcher(powerOkConfig, psPowerOKHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302694 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302695 else
2696 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002697 lg2::error("PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002698 return -1;
2699 }
2700
Lei YU92caa4c2021-02-23 16:59:25 +08002701 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002702 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05302703 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302704 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302705 {
Priyatharshan P70120512020-09-16 18:47:20 +05302706 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002707 sioPowerGoodHandler, sioPowerGoodLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302708 sioPowerGoodEvent))
2709 {
2710 return -1;
2711 }
2712 }
2713 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
2714 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002715 static sdbusplus::bus::match_t sioPwrGoodEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002716 power_control::dbusGPIOMatcher(sioPwrGoodConfig,
2717 sioPowerGoodHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302718 }
2719 else
2720 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002721 lg2::error(
Priyatharshan P70120512020-09-16 18:47:20 +05302722 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302723 return -1;
2724 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002725
Priyatharshan P19c47a32020-08-12 18:16:43 +05302726 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302727 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302728 {
Priyatharshan P70120512020-09-16 18:47:20 +05302729 if (!requestGPIOEvents(sioOnControlConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002730 sioOnControlHandler, sioOnControlLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302731 sioOnControlEvent))
2732 {
2733 return -1;
2734 }
2735 }
2736 else if (sioOnControlConfig.type == ConfigType::DBUS)
2737 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002738 static sdbusplus::bus::match_t sioOnControlEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002739 power_control::dbusGPIOMatcher(sioOnControlConfig,
2740 sioOnControlHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302741 }
2742 else
2743 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002744 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002745 "sioOnControl name should be configured from jsonconfig file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302746 return -1;
2747 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002748
Priyatharshan P19c47a32020-08-12 18:16:43 +05302749 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302750 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302751 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002752 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
Priyatharshan P70120512020-09-16 18:47:20 +05302753 sioS5Line, sioS5Event))
2754 {
2755 return -1;
2756 }
2757 }
2758 else if (sioS5Config.type == ConfigType::DBUS)
2759 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002760 static sdbusplus::bus::match_t sioS5EventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002761 power_control::dbusGPIOMatcher(sioS5Config, sioS5Handler);
Priyatharshan P70120512020-09-16 18:47:20 +05302762 }
2763 else
2764 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002765 lg2::error("sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302766 return -1;
2767 }
2768 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002769
2770 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302771 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002772 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002773 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
2774 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302775 {
2776 return -1;
2777 }
2778 }
Priyatharshan P70120512020-09-16 18:47:20 +05302779 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302780 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002781 static sdbusplus::bus::match_t powerButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002782 power_control::dbusGPIOMatcher(powerButtonConfig,
2783 powerButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002784 }
2785
2786 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302787 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002788 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002789 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
2790 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302791 {
2792 return -1;
2793 }
2794 }
Priyatharshan P70120512020-09-16 18:47:20 +05302795 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302796 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002797 static sdbusplus::bus::match_t resetButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002798 power_control::dbusGPIOMatcher(resetButtonConfig,
2799 resetButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002800 }
2801
2802 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302803 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302804 {
Priyatharshan P70120512020-09-16 18:47:20 +05302805 if (!nmiButtonConfig.lineName.empty())
2806 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002807 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302808 nmiButtonLine, nmiButtonEvent);
2809 }
2810 }
2811 else if (nmiButtonConfig.type == ConfigType::DBUS)
2812 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002813 static sdbusplus::bus::match_t nmiButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002814 power_control::dbusGPIOMatcher(nmiButtonConfig, nmiButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302815 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002816
2817 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302818 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302819 {
Priyatharshan P70120512020-09-16 18:47:20 +05302820 if (!idButtonConfig.lineName.empty())
2821 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002822 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302823 idButtonLine, idButtonEvent);
2824 }
2825 }
2826 else if (idButtonConfig.type == ConfigType::DBUS)
2827 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002828 static sdbusplus::bus::match_t idButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002829 power_control::dbusGPIOMatcher(idButtonConfig, idButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302830 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002831
Jason M. Billsfb957332021-01-28 13:18:46 -08002832#ifdef USE_PLT_RST
Patrick Williams439b9c32022-07-22 19:26:53 -05002833 sdbusplus::bus::match_t pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08002834 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08002835 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2836 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08002837 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08002838#endif
2839
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002840 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302841 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002842 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002843 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
2844 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302845 {
2846 return -1;
2847 }
2848 }
Priyatharshan P70120512020-09-16 18:47:20 +05302849 else if (postCompleteConfig.type == ConfigType::DBUS)
2850 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002851 static sdbusplus::bus::match_t postCompleteEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002852 power_control::dbusGPIOMatcher(postCompleteConfig,
2853 postCompleteHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302854 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302855 else
2856 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002857 lg2::error(
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002858 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002859 return -1;
2860 }
2861
2862 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05302863 if (!nmiOutConfig.lineName.empty())
2864 {
Jian Zhang461a1662022-09-22 11:29:01 +08002865 setGPIOOutput(nmiOutConfig.lineName, !nmiOutConfig.polarity,
2866 nmiOutLine);
Priyatharshan P70120512020-09-16 18:47:20 +05302867 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002868
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002869 // Initialize POWER_OUT and RESET_OUT GPIO.
2870 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05302871 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002872 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002873 if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
2874 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302875 {
2876 return -1;
2877 }
2878 }
2879 else
2880 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002881 lg2::error("powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002882 return -1;
2883 }
2884
Priyatharshan P70120512020-09-16 18:47:20 +05302885 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002886 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002887 if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
2888 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302889 {
2890 return -1;
2891 }
2892 }
2893 else
2894 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002895 lg2::error("ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002896 return -1;
2897 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002898 // Release line
2899 line.reset();
2900
Matt Simmering58e379d2022-09-23 14:45:50 -07002901 // Initialize the power state and operating system state
Lei YU92caa4c2021-02-23 16:59:25 +08002902 powerState = PowerState::off;
Matt Simmering58e379d2022-09-23 14:45:50 -07002903 operatingSystemState = OperatingSystemStateStage::Inactive;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002904 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05302905
2906 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002907 {
Jean-Marie Verdun61b4a5b2021-09-19 08:53:28 -04002908 if (psPowerOKLine.get_value() > 0 ||
Lei YUa37c2472021-09-26 15:57:12 +08002909 (sioEnabled &&
2910 (sioPowerGoodLine.get_value() == sioPwrGoodConfig.polarity)))
Priyatharshan P70120512020-09-16 18:47:20 +05302911 {
2912 powerState = PowerState::on;
2913 }
2914 }
2915 else
2916 {
2917 if (getProperty(powerOkConfig))
2918 {
2919 powerState = PowerState::on;
2920 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002921 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002922 // Check if we need to start the Power Restore policy
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03002923 if (powerState != PowerState::on)
2924 {
2925 powerRestore.run();
2926 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002927
Lei YU92caa4c2021-02-23 16:59:25 +08002928 if (nmiOutLine)
2929 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002930
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002931 lg2::info("Initializing power state.");
Lei YU92caa4c2021-02-23 16:59:25 +08002932 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002933
2934 // Power Control Service
2935 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002936 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002937
2938 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05302939 hostIface =
2940 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
2941 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002942 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08002943 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002944 "RequestedHostTransition",
2945 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2946 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002947 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2948 {
2949 // if power button is masked, ignore this
2950 if (!powerButtonMask)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002951 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002952 sendPowerControlEvent(Event::gracefulPowerOffRequest);
2953 addRestartCause(RestartCause::command);
Jason M. Billse7520ba2020-01-31 11:19:03 -08002954 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002955 else
2956 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05002957 lg2::info("Power Button Masked.");
2958 throw std::invalid_argument("Transition Request Masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002959 return 0;
2960 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05002961 }
2962 else if (requested == "xyz.openbmc_project.State.Host.Transition.On")
2963 {
2964 // if power button is masked, ignore this
2965 if (!powerButtonMask)
2966 {
2967 sendPowerControlEvent(Event::powerOnRequest);
2968 addRestartCause(RestartCause::command);
2969 }
2970 else
2971 {
2972 lg2::info("Power Button Masked.");
2973 throw std::invalid_argument("Transition Request Masked");
2974 return 0;
2975 }
2976 }
2977 else if (requested ==
2978 "xyz.openbmc_project.State.Host.Transition.Reboot")
2979 {
2980 // if power button is masked, ignore this
2981 if (!powerButtonMask)
2982 {
2983 sendPowerControlEvent(Event::powerCycleRequest);
2984 addRestartCause(RestartCause::command);
2985 }
2986 else
2987 {
2988 lg2::info("Power Button Masked.");
2989 throw std::invalid_argument("Transition Request Masked");
2990 return 0;
2991 }
2992 }
2993 else if (requested ==
2994 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot")
2995 {
2996 // if reset button is masked, ignore this
2997 if (!resetButtonMask)
2998 {
2999 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
3000 addRestartCause(RestartCause::command);
3001 }
3002 else
3003 {
3004 lg2::info("Reset Button Masked.");
3005 throw std::invalid_argument("Transition Request Masked");
3006 return 0;
3007 }
3008 }
3009 else if (requested ==
3010 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot")
3011 {
3012 // if reset button is masked, ignore this
3013 if (!resetButtonMask)
3014 {
3015 sendPowerControlEvent(Event::resetRequest);
3016 addRestartCause(RestartCause::command);
3017 }
3018 else
3019 {
3020 lg2::info("Reset Button Masked.");
3021 throw std::invalid_argument("Transition Request Masked");
3022 return 0;
3023 }
3024 }
3025 else
3026 {
3027 lg2::error("Unrecognized host state transition request.");
3028 throw std::invalid_argument("Unrecognized Transition Request");
3029 return 0;
3030 }
3031 resp = requested;
3032 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003033 });
Lei YU92caa4c2021-02-23 16:59:25 +08003034 hostIface->register_property("CurrentHostState",
3035 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003036
Lei YU92caa4c2021-02-23 16:59:25 +08003037 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003038
3039 // Chassis Control Service
3040 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003041 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003042
3043 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003044 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05303045 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003046 "xyz.openbmc_project.State.Chassis");
3047
Lei YU92caa4c2021-02-23 16:59:25 +08003048 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003049 "RequestedPowerTransition",
3050 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
3051 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003052 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
3053 {
3054 // if power button is masked, ignore this
3055 if (!powerButtonMask)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003056 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003057 sendPowerControlEvent(Event::powerOffRequest);
3058 addRestartCause(RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003059 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003060 else
3061 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003062 lg2::info("Power Button Masked.");
3063 throw std::invalid_argument("Transition Request Masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003064 return 0;
3065 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003066 }
3067 else if (requested == "xyz.openbmc_project.State.Chassis.Transition.On")
3068 {
3069 // if power button is masked, ignore this
3070 if (!powerButtonMask)
3071 {
3072 sendPowerControlEvent(Event::powerOnRequest);
3073 addRestartCause(RestartCause::command);
3074 }
3075 else
3076 {
3077 lg2::info("Power Button Masked.");
3078 throw std::invalid_argument("Transition Request Masked");
3079 return 0;
3080 }
3081 }
3082 else if (requested ==
3083 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3084 {
3085 // if power button is masked, ignore this
3086 if (!powerButtonMask)
3087 {
3088 sendPowerControlEvent(Event::powerCycleRequest);
3089 addRestartCause(RestartCause::command);
3090 }
3091 else
3092 {
3093 lg2::info("Power Button Masked.");
3094 throw std::invalid_argument("Transition Request Masked");
3095 return 0;
3096 }
3097 }
3098 else
3099 {
3100 lg2::error("Unrecognized chassis state transition request.");
3101 throw std::invalid_argument("Unrecognized Transition Request");
3102 return 0;
3103 }
3104 resp = requested;
3105 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003106 });
Lei YU92caa4c2021-02-23 16:59:25 +08003107 chassisIface->register_property("CurrentPowerState",
3108 std::string(getChassisState(powerState)));
3109 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003110
Lei YU92caa4c2021-02-23 16:59:25 +08003111 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003112
Vijay Khemka04175c22020-10-09 14:28:11 -07003113#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003114 // Chassis System Service
3115 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003116 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003117
3118 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003119 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003120 "/xyz/openbmc_project/state/chassis_system0",
3121 "xyz.openbmc_project.State.Chassis");
3122
Lei YU92caa4c2021-02-23 16:59:25 +08003123 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003124 "RequestedPowerTransition",
3125 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3126 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003127 if (requested ==
3128 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3129 {
3130 systemReset();
3131 addRestartCause(RestartCause::command);
3132 }
3133 else
3134 {
3135 lg2::error("Unrecognized chassis system state transition request.");
3136 throw std::invalid_argument("Unrecognized Transition Request");
3137 return 0;
3138 }
3139 resp = requested;
3140 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003141 });
Lei YU92caa4c2021-02-23 16:59:25 +08003142 chassisSysIface->register_property(
3143 "CurrentPowerState", std::string(getChassisState(powerState)));
3144 chassisSysIface->register_property("LastStateChangeTime",
3145 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003146
Lei YU92caa4c2021-02-23 16:59:25 +08003147 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003148
Naveen Moses117c34e2021-05-26 20:10:51 +05303149 if (!slotPowerConfig.lineName.empty())
3150 {
3151 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3152 {
3153 return -1;
3154 }
3155
3156 slotPowerState = SlotPowerState::off;
3157 if (slotPowerLine.get_value() > 0)
3158 {
3159 slotPowerState = SlotPowerState::on;
3160 }
3161
3162 chassisSlotIface = chassisSysServer.add_interface(
3163 "/xyz/openbmc_project/state/chassis_system" + node,
3164 "xyz.openbmc_project.State.Chassis");
3165 chassisSlotIface->register_property(
3166 "RequestedPowerTransition",
3167 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3168 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003169 if (requested == "xyz.openbmc_project.State.Chassis.Transition.On")
3170 {
3171 slotPowerOn();
3172 }
3173 else if (requested ==
3174 "xyz.openbmc_project.State.Chassis.Transition.Off")
3175 {
3176 slotPowerOff();
3177 }
3178 else if (requested ==
3179 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3180 {
3181 slotPowerCycle();
3182 }
3183 else
3184 {
3185 lg2::error(
3186 "Unrecognized chassis system state transition request.\n");
3187 throw std::invalid_argument("Unrecognized Transition Request");
3188 return 0;
3189 }
3190 resp = requested;
3191 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003192 });
Naveen Moses117c34e2021-05-26 20:10:51 +05303193 chassisSlotIface->register_property(
3194 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3195 chassisSlotIface->register_property("LastStateChangeTime",
3196 getCurrentTimeMs());
3197 chassisSlotIface->initialize();
3198 }
3199#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003200 // Buttons Service
3201 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003202 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003203
Priyatharshan P70120512020-09-16 18:47:20 +05303204 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003205 {
Priyatharshan P70120512020-09-16 18:47:20 +05303206 // Power Button Interface
3207 power_control::powerButtonIface = buttonsServer.add_interface(
3208 "/xyz/openbmc_project/chassis/buttons/power",
3209 "xyz.openbmc_project.Chassis.Buttons");
3210
3211 powerButtonIface->register_property(
Patrick Williamsd394c882023-10-20 11:18:44 -05003212 "ButtonMasked", false, [](const bool requested, bool& current) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003213 if (requested)
3214 {
3215 if (powerButtonMask)
Priyatharshan P70120512020-09-16 18:47:20 +05303216 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003217 return 1;
Priyatharshan P70120512020-09-16 18:47:20 +05303218 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003219 if (!setGPIOOutput(powerOutConfig.lineName,
3220 !powerOutConfig.polarity, powerButtonMask))
Priyatharshan P70120512020-09-16 18:47:20 +05303221 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003222 throw std::runtime_error("Failed to request GPIO");
3223 return 0;
Priyatharshan P70120512020-09-16 18:47:20 +05303224 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003225 lg2::info("Power Button Masked.");
3226 }
3227 else
3228 {
3229 if (!powerButtonMask)
3230 {
3231 return 1;
3232 }
3233 lg2::info("Power Button Un-masked");
3234 powerButtonMask.reset();
3235 }
3236 // Update the mask setting
3237 current = requested;
3238 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003239 });
Priyatharshan P70120512020-09-16 18:47:20 +05303240
3241 // Check power button state
3242 bool powerButtonPressed;
3243 if (powerButtonConfig.type == ConfigType::GPIO)
3244 {
3245 powerButtonPressed = powerButtonLine.get_value() == 0;
3246 }
3247 else
3248 {
3249 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3250 }
3251
3252 powerButtonIface->register_property("ButtonPressed",
3253 powerButtonPressed);
3254
3255 powerButtonIface->initialize();
3256 }
3257
3258 if (!resetButtonConfig.lineName.empty())
3259 {
3260 // Reset Button Interface
3261
Lei YU92caa4c2021-02-23 16:59:25 +08003262 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003263 "/xyz/openbmc_project/chassis/buttons/reset",
3264 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003265
Lei YU92caa4c2021-02-23 16:59:25 +08003266 resetButtonIface->register_property(
Patrick Williamsd394c882023-10-20 11:18:44 -05003267 "ButtonMasked", false, [](const bool requested, bool& current) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003268 if (requested)
3269 {
3270 if (resetButtonMask)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003271 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003272 return 1;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003273 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003274 if (!setGPIOOutput(resetOutConfig.lineName,
3275 !resetOutConfig.polarity, resetButtonMask))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003276 {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003277 throw std::runtime_error("Failed to request GPIO");
3278 return 0;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003279 }
Patrick Williams48aa1f02023-05-10 07:50:30 -05003280 lg2::info("Reset Button Masked.");
3281 }
3282 else
3283 {
3284 if (!resetButtonMask)
3285 {
3286 return 1;
3287 }
3288 lg2::info("Reset Button Un-masked");
3289 resetButtonMask.reset();
3290 }
3291 // Update the mask setting
3292 current = requested;
3293 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003294 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003295
John Wang6c090072020-09-30 13:32:16 +08003296 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303297 bool resetButtonPressed;
3298 if (resetButtonConfig.type == ConfigType::GPIO)
3299 {
3300 resetButtonPressed = resetButtonLine.get_value() == 0;
3301 }
3302 else
3303 {
3304 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3305 }
3306
Lei YU92caa4c2021-02-23 16:59:25 +08003307 resetButtonIface->register_property("ButtonPressed",
3308 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003309
Lei YU92caa4c2021-02-23 16:59:25 +08003310 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003311 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003312
Lei YU92caa4c2021-02-23 16:59:25 +08003313 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003314 {
3315 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003316 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003317 "/xyz/openbmc_project/chassis/buttons/nmi",
3318 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003319
Lei YU92caa4c2021-02-23 16:59:25 +08003320 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003321 "ButtonMasked", false, [](const bool requested, bool& current) {
Patrick Williamsd394c882023-10-20 11:18:44 -05003322 if (nmiButtonMasked == requested)
3323 {
3324 // NMI button mask is already set as requested, so no change
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003325 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003326 }
3327 if (requested)
3328 {
3329 lg2::info("NMI Button Masked.");
3330 nmiButtonMasked = true;
3331 }
3332 else
3333 {
3334 lg2::info("NMI Button Un-masked.");
3335 nmiButtonMasked = false;
3336 }
3337 // Update the mask setting
3338 current = nmiButtonMasked;
3339 return 1;
3340 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003341
Vijay Khemka33a532d2019-11-14 16:50:35 -08003342 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303343 bool nmiButtonPressed;
3344 if (nmiButtonConfig.type == ConfigType::GPIO)
3345 {
3346 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3347 }
3348 else
3349 {
3350 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3351 }
3352
Lei YU92caa4c2021-02-23 16:59:25 +08003353 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003354
Lei YU92caa4c2021-02-23 16:59:25 +08003355 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003356 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003357
Lei YU92caa4c2021-02-23 16:59:25 +08003358 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003359 {
3360 // NMI out Service
3361 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003362 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003363
Vijay Khemka33a532d2019-11-14 16:50:35 -08003364 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303365 nmiOutIface = nmiOutServer.add_interface(
3366 "/xyz/openbmc_project/control/host" + node + "/nmi",
3367 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003368 nmiOutIface->register_method("NMI", nmiReset);
3369 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003370 }
Chen Yugang174ec662019-08-19 19:58:49 +08003371
Lei YU92caa4c2021-02-23 16:59:25 +08003372 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003373 {
3374 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003375 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003376 "/xyz/openbmc_project/chassis/buttons/id",
3377 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003378
Vijay Khemka33a532d2019-11-14 16:50:35 -08003379 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303380 bool idButtonPressed;
3381 if (idButtonConfig.type == ConfigType::GPIO)
3382 {
3383 idButtonPressed = idButtonLine.get_value() == 0;
3384 }
3385 else
3386 {
3387 idButtonPressed = getProperty(idButtonConfig) == 0;
3388 }
3389
Lei YU92caa4c2021-02-23 16:59:25 +08003390 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003391
Lei YU92caa4c2021-02-23 16:59:25 +08003392 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003393 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003394
3395 // OS State Service
3396 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003397 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003398
3399 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003400 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003401 "/xyz/openbmc_project/state/os",
3402 "xyz.openbmc_project.State.OperatingSystem.Status");
3403
3404 // Get the initial OS state based on POST complete
3405 // 0: Asserted, OS state is "Standby" (ready to boot)
3406 // 1: De-Asserted, OS state is "Inactive"
Tim Lee86239182021-12-23 11:46:01 +08003407 OperatingSystemStateStage osState;
Priyatharshan P70120512020-09-16 18:47:20 +05303408 if (postCompleteConfig.type == ConfigType::GPIO)
3409 {
Tim Lee86239182021-12-23 11:46:01 +08003410 osState = postCompleteLine.get_value() > 0
3411 ? OperatingSystemStateStage::Inactive
3412 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303413 }
3414 else
3415 {
Tim Lee86239182021-12-23 11:46:01 +08003416 osState = getProperty(postCompleteConfig) > 0
3417 ? OperatingSystemStateStage::Inactive
3418 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303419 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003420
Tim Lee86239182021-12-23 11:46:01 +08003421 osIface->register_property(
3422 "OperatingSystemState",
3423 std::string(getOperatingSystemStateStage(osState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003424
Lei YU92caa4c2021-02-23 16:59:25 +08003425 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003426
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003427 // Restart Cause Service
3428 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003429 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003430
3431 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003432 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303433 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003434 "xyz.openbmc_project.Control.Host.RestartCause");
3435
Lei YU92caa4c2021-02-23 16:59:25 +08003436 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003437 "RestartCause",
3438 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3439
Lei YU92caa4c2021-02-23 16:59:25 +08003440 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003441 "RequestedRestartCause",
3442 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3443 [](const std::string& requested, std::string& resp) {
Patrick Williams48aa1f02023-05-10 07:50:30 -05003444 if (requested ==
3445 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3446 {
3447 addRestartCause(RestartCause::watchdog);
3448 }
3449 else
3450 {
3451 throw std::invalid_argument("Unrecognized RestartCause Request");
3452 return 0;
3453 }
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003454
Patrick Williams48aa1f02023-05-10 07:50:30 -05003455 lg2::info("RestartCause requested: {RESTART_CAUSE}", "RESTART_CAUSE",
3456 requested);
3457 resp = requested;
3458 return 1;
Patrick Williamsd394c882023-10-20 11:18:44 -05003459 });
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003460
Lei YU92caa4c2021-02-23 16:59:25 +08003461 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003462
Lei YU92caa4c2021-02-23 16:59:25 +08003463 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003464
Lei YU92caa4c2021-02-23 16:59:25 +08003465 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003466
3467 return 0;
3468}