blob: 6229251655e92950555df2439b93bccabe030619 [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
Jason M. Billse63dea02020-08-27 12:07:35 -070021#include <boost/asio/io_service.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{
37static boost::asio::io_service io;
38std::shared_ptr<sdbusplus::asio::connection> conn;
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +030039PersistentState appState;
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +030040PowerRestoreController powerRestore(io);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053041
42static std::string node = "0";
Andrei Kartashev3efcf372021-12-29 15:32:17 +030043static const std::string appName = "power-control";
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053044
Priyatharshan P70120512020-09-16 18:47:20 +053045enum class DbusConfigType
46{
47 name = 1,
48 path,
49 interface,
50 property
51};
52boost::container::flat_map<DbusConfigType, std::string> dbusParams = {
53 {DbusConfigType::name, "DbusName"},
54 {DbusConfigType::path, "Path"},
55 {DbusConfigType::interface, "Interface"},
56 {DbusConfigType::property, "Property"}};
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053057
Priyatharshan P70120512020-09-16 18:47:20 +053058enum class ConfigType
59{
60 GPIO = 1,
61 DBUS
62};
63
64struct ConfigData
65{
66 std::string name;
67 std::string lineName;
68 std::string dbusName;
69 std::string path;
70 std::string interface;
Jean-Marie Verdun50937e72021-08-31 09:15:49 -070071 bool polarity;
Priyatharshan P70120512020-09-16 18:47:20 +053072 ConfigType type;
73};
74
75static ConfigData powerOutConfig;
76static ConfigData powerOkConfig;
77static ConfigData resetOutConfig;
78static ConfigData nmiOutConfig;
79static ConfigData sioPwrGoodConfig;
80static ConfigData sioOnControlConfig;
81static ConfigData sioS5Config;
82static ConfigData postCompleteConfig;
83static ConfigData powerButtonConfig;
84static ConfigData resetButtonConfig;
85static ConfigData idButtonConfig;
86static ConfigData nmiButtonConfig;
Naveen Moses117c34e2021-05-26 20:10:51 +053087static ConfigData slotPowerConfig;
88
Priyatharshan P70120512020-09-16 18:47:20 +053089// map for storing list of gpio parameters whose config are to be read from x86
90// power control json config
91boost::container::flat_map<std::string, ConfigData*> powerSignalMap = {
92 {"PowerOut", &powerOutConfig},
93 {"PowerOk", &powerOkConfig},
94 {"ResetOut", &resetOutConfig},
95 {"NMIOut", &nmiOutConfig},
96 {"SioPowerGood", &sioPwrGoodConfig},
97 {"SioOnControl", &sioOnControlConfig},
98 {"SIOS5", &sioS5Config},
99 {"PostComplete", &postCompleteConfig},
100 {"PowerButton", &powerButtonConfig},
101 {"ResetButton", &resetButtonConfig},
102 {"IdButton", &idButtonConfig},
Naveen Moses117c34e2021-05-26 20:10:51 +0530103 {"NMIButton", &nmiButtonConfig},
104 {"SlotPower", &slotPowerConfig}};
Priyatharshan P70120512020-09-16 18:47:20 +0530105
106static std::string hostDbusName = "xyz.openbmc_project.State.Host";
107static std::string chassisDbusName = "xyz.openbmc_project.State.Chassis";
108static std::string osDbusName = "xyz.openbmc_project.State.OperatingSystem";
109static std::string buttonDbusName = "xyz.openbmc_project.Chassis.Buttons";
110static std::string nmiDbusName = "xyz.openbmc_project.Control.Host.NMI";
111static std::string rstCauseDbusName =
112 "xyz.openbmc_project.Control.Host.RestartCause";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700113static std::shared_ptr<sdbusplus::asio::dbus_interface> hostIface;
114static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700115#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -0700116static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSysIface;
Naveen Moses117c34e2021-05-26 20:10:51 +0530117static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSlotIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700118#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700119static std::shared_ptr<sdbusplus::asio::dbus_interface> powerButtonIface;
120static std::shared_ptr<sdbusplus::asio::dbus_interface> resetButtonIface;
121static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiButtonIface;
122static std::shared_ptr<sdbusplus::asio::dbus_interface> osIface;
123static std::shared_ptr<sdbusplus::asio::dbus_interface> idButtonIface;
Chen Yugang174ec662019-08-19 19:58:49 +0800124static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiOutIface;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700125static std::shared_ptr<sdbusplus::asio::dbus_interface> restartCauseIface;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700126
127static gpiod::line powerButtonMask;
128static gpiod::line resetButtonMask;
129static bool nmiButtonMasked = false;
Matt Simmering58e379d2022-09-23 14:45:50 -0700130#if IGNORE_SOFT_RESETS_DURING_POST
131static bool ignoreNextSoftReset = false;
132#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700133
Priyatharshan P70120512020-09-16 18:47:20 +0530134// This map contains all timer values that are to be read from json config
135boost::container::flat_map<std::string, int> TimerMap = {
Jason M. Billsaeefe042021-09-08 14:56:11 -0700136 {"PowerPulseMs", 200},
137 {"ForceOffPulseMs", 15000},
138 {"ResetPulseMs", 500},
139 {"PowerCycleMs", 5000},
140 {"SioPowerGoodWatchdogMs", 1000},
141 {"PsPowerOKWatchdogMs", 8000},
142 {"GracefulPowerOffS", (5 * 60)},
143 {"WarmResetCheckMs", 500},
144 {"PowerOffSaveMs", 7000},
145 {"SlotPowerCycleMs", 200}};
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700146
147static bool nmiEnabled = true;
Priyatharshan P19c47a32020-08-12 18:16:43 +0530148static bool sioEnabled = true;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700149
150// Timers
151// Time holding GPIOs asserted
152static boost::asio::steady_timer gpioAssertTimer(io);
153// Time between off and on during a power cycle
154static boost::asio::steady_timer powerCycleTimer(io);
155// Time OS gracefully powering off
156static boost::asio::steady_timer gracefulPowerOffTimer(io);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700157// Time the warm reset check
158static boost::asio::steady_timer warmResetCheckTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700159// Time power supply power OK assertion on power-on
160static boost::asio::steady_timer psPowerOKWatchdogTimer(io);
161// Time SIO power good assertion on power-on
162static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io);
163// Time power-off state save for power loss tracking
164static boost::asio::steady_timer powerStateSaveTimer(io);
165// POH timer
166static boost::asio::steady_timer pohCounterTimer(io);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700167// Time when to allow restart cause updates
168static boost::asio::steady_timer restartCauseTimer(io);
Naveen Moses117c34e2021-05-26 20:10:51 +0530169static boost::asio::steady_timer slotPowerCycleTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700170
171// GPIO Lines and Event Descriptors
172static gpiod::line psPowerOKLine;
173static boost::asio::posix::stream_descriptor psPowerOKEvent(io);
174static gpiod::line sioPowerGoodLine;
175static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io);
176static gpiod::line sioOnControlLine;
177static boost::asio::posix::stream_descriptor sioOnControlEvent(io);
178static gpiod::line sioS5Line;
179static boost::asio::posix::stream_descriptor sioS5Event(io);
180static gpiod::line powerButtonLine;
181static boost::asio::posix::stream_descriptor powerButtonEvent(io);
182static gpiod::line resetButtonLine;
183static boost::asio::posix::stream_descriptor resetButtonEvent(io);
184static gpiod::line nmiButtonLine;
185static boost::asio::posix::stream_descriptor nmiButtonEvent(io);
186static gpiod::line idButtonLine;
187static boost::asio::posix::stream_descriptor idButtonEvent(io);
188static gpiod::line postCompleteLine;
189static boost::asio::posix::stream_descriptor postCompleteEvent(io);
190static gpiod::line nmiOutLine;
Naveen Moses117c34e2021-05-26 20:10:51 +0530191static gpiod::line slotPowerLine;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700192
193static constexpr uint8_t beepPowerFail = 8;
194
195static void beep(const uint8_t& beepPriority)
196{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800197 lg2::info("Beep with priority: {BEEP_PRIORITY}", "BEEP_PRIORITY",
198 beepPriority);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700199
200 conn->async_method_call(
201 [](boost::system::error_code ec) {
202 if (ec)
203 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800204 lg2::error(
205 "beep returned error with async_method_call (ec = {ERROR_MSG})",
206 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700207 return;
208 }
209 },
210 "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
211 "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
212}
213
Tim Lee86239182021-12-23 11:46:01 +0800214enum class OperatingSystemStateStage
215{
216 Inactive,
217 Standby,
218};
Matt Simmering58e379d2022-09-23 14:45:50 -0700219static OperatingSystemStateStage operatingSystemState;
Tim Lee86239182021-12-23 11:46:01 +0800220static constexpr std::string_view
221 getOperatingSystemStateStage(const OperatingSystemStateStage stage)
222{
223 switch (stage)
224 {
225 case OperatingSystemStateStage::Inactive:
226 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
227 break;
228 case OperatingSystemStateStage::Standby:
229 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Standby";
230 break;
231 default:
232 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
233 break;
234 }
235};
236static void setOperatingSystemState(const OperatingSystemStateStage stage)
237{
Matt Simmering58e379d2022-09-23 14:45:50 -0700238 operatingSystemState = stage;
239#if IGNORE_SOFT_RESETS_DURING_POST
240 // If POST complete has asserted set ignoreNextSoftReset to false to avoid
241 // masking soft resets after POST
242 if (operatingSystemState == OperatingSystemStateStage::Standby)
243 {
244 ignoreNextSoftReset = false;
245 }
246#endif
Tim Lee86239182021-12-23 11:46:01 +0800247 osIface->set_property("OperatingSystemState",
248 std::string(getOperatingSystemStateStage(stage)));
249
250 lg2::info("Moving os state to {STATE} stage", "STATE",
251 getOperatingSystemStateStage(stage));
252}
253
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700254enum class PowerState
255{
256 on,
257 waitForPSPowerOK,
258 waitForSIOPowerGood,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700259 off,
260 transitionToOff,
261 gracefulTransitionToOff,
262 cycleOff,
263 transitionToCycleOff,
264 gracefulTransitionToCycleOff,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700265 checkForWarmReset,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700266};
267static PowerState powerState;
268static std::string getPowerStateName(PowerState state)
269{
270 switch (state)
271 {
272 case PowerState::on:
273 return "On";
274 break;
275 case PowerState::waitForPSPowerOK:
276 return "Wait for Power Supply Power OK";
277 break;
278 case PowerState::waitForSIOPowerGood:
279 return "Wait for SIO Power Good";
280 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700281 case PowerState::off:
282 return "Off";
283 break;
284 case PowerState::transitionToOff:
285 return "Transition to Off";
286 break;
287 case PowerState::gracefulTransitionToOff:
288 return "Graceful Transition to Off";
289 break;
290 case PowerState::cycleOff:
291 return "Power Cycle Off";
292 break;
293 case PowerState::transitionToCycleOff:
294 return "Transition to Power Cycle Off";
295 break;
296 case PowerState::gracefulTransitionToCycleOff:
297 return "Graceful Transition to Power Cycle Off";
298 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700299 case PowerState::checkForWarmReset:
300 return "Check for Warm Reset";
301 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700302 default:
303 return "unknown state: " + std::to_string(static_cast<int>(state));
304 break;
305 }
306}
307static void logStateTransition(const PowerState state)
308{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800309 lg2::info("Host{HOST}: Moving to \"{STATE}\" state", "HOST", node, "STATE",
310 getPowerStateName(state));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700311}
312
313enum class Event
314{
315 psPowerOKAssert,
316 psPowerOKDeAssert,
317 sioPowerGoodAssert,
318 sioPowerGoodDeAssert,
319 sioS5Assert,
320 sioS5DeAssert,
Jason M. Billsfb957332021-01-28 13:18:46 -0800321 pltRstAssert,
322 pltRstDeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700323 postCompleteAssert,
324 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700325 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700326 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700327 powerCycleTimerExpired,
328 psPowerOKWatchdogTimerExpired,
329 sioPowerGoodWatchdogTimerExpired,
330 gracefulPowerOffTimerExpired,
331 powerOnRequest,
332 powerOffRequest,
333 powerCycleRequest,
334 resetRequest,
335 gracefulPowerOffRequest,
336 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700337 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700338};
339static std::string getEventName(Event event)
340{
341 switch (event)
342 {
343 case Event::psPowerOKAssert:
344 return "power supply power OK assert";
345 break;
346 case Event::psPowerOKDeAssert:
347 return "power supply power OK de-assert";
348 break;
349 case Event::sioPowerGoodAssert:
350 return "SIO power good assert";
351 break;
352 case Event::sioPowerGoodDeAssert:
353 return "SIO power good de-assert";
354 break;
355 case Event::sioS5Assert:
356 return "SIO S5 assert";
357 break;
358 case Event::sioS5DeAssert:
359 return "SIO S5 de-assert";
360 break;
Jason M. Billsfb957332021-01-28 13:18:46 -0800361 case Event::pltRstAssert:
362 return "PLT_RST assert";
363 break;
364 case Event::pltRstDeAssert:
365 return "PLT_RST de-assert";
366 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700367 case Event::postCompleteAssert:
368 return "POST Complete assert";
369 break;
370 case Event::postCompleteDeAssert:
371 return "POST Complete de-assert";
372 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700373 case Event::powerButtonPressed:
374 return "power button pressed";
375 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700376 case Event::resetButtonPressed:
377 return "reset button pressed";
378 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700379 case Event::powerCycleTimerExpired:
380 return "power cycle timer expired";
381 break;
382 case Event::psPowerOKWatchdogTimerExpired:
383 return "power supply power OK watchdog timer expired";
384 break;
385 case Event::sioPowerGoodWatchdogTimerExpired:
386 return "SIO power good watchdog timer expired";
387 break;
388 case Event::gracefulPowerOffTimerExpired:
389 return "graceful power-off timer expired";
390 break;
391 case Event::powerOnRequest:
392 return "power-on request";
393 break;
394 case Event::powerOffRequest:
395 return "power-off request";
396 break;
397 case Event::powerCycleRequest:
398 return "power-cycle request";
399 break;
400 case Event::resetRequest:
401 return "reset request";
402 break;
403 case Event::gracefulPowerOffRequest:
404 return "graceful power-off request";
405 break;
406 case Event::gracefulPowerCycleRequest:
407 return "graceful power-cycle request";
408 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700409 case Event::warmResetDetected:
410 return "warm reset detected";
411 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700412 default:
413 return "unknown event: " + std::to_string(static_cast<int>(event));
414 break;
415 }
416}
417static void logEvent(const std::string_view stateHandler, const Event event)
418{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800419 lg2::info("{STATE_HANDLER}: {EVENT} event received", "STATE_HANDLER",
420 stateHandler, "EVENT", getEventName(event));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700421}
422
423// Power state handlers
424static void powerStateOn(const Event event);
425static void powerStateWaitForPSPowerOK(const Event event);
426static void powerStateWaitForSIOPowerGood(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700427static void powerStateOff(const Event event);
428static void powerStateTransitionToOff(const Event event);
429static void powerStateGracefulTransitionToOff(const Event event);
430static void powerStateCycleOff(const Event event);
431static void powerStateTransitionToCycleOff(const Event event);
432static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700433static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700434
435static std::function<void(const Event)> getPowerStateHandler(PowerState state)
436{
437 switch (state)
438 {
439 case PowerState::on:
440 return powerStateOn;
441 break;
442 case PowerState::waitForPSPowerOK:
443 return powerStateWaitForPSPowerOK;
444 break;
445 case PowerState::waitForSIOPowerGood:
446 return powerStateWaitForSIOPowerGood;
447 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700448 case PowerState::off:
449 return powerStateOff;
450 break;
451 case PowerState::transitionToOff:
452 return powerStateTransitionToOff;
453 break;
454 case PowerState::gracefulTransitionToOff:
455 return powerStateGracefulTransitionToOff;
456 break;
457 case PowerState::cycleOff:
458 return powerStateCycleOff;
459 break;
460 case PowerState::transitionToCycleOff:
461 return powerStateTransitionToCycleOff;
462 break;
463 case PowerState::gracefulTransitionToCycleOff:
464 return powerStateGracefulTransitionToCycleOff;
465 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700466 case PowerState::checkForWarmReset:
467 return powerStateCheckForWarmReset;
468 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700469 default:
Zev Weiss047bcb52020-08-20 21:28:11 +0000470 return nullptr;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700471 break;
472 }
473};
474
475static void sendPowerControlEvent(const Event event)
476{
477 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
478 if (handler == nullptr)
479 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800480 lg2::error("Failed to find handler for power state: {STATE}", "STATE",
481 static_cast<int>(powerState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700482 return;
483 }
484 handler(event);
485}
486
487static uint64_t getCurrentTimeMs()
488{
489 struct timespec time = {};
490
491 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
492 {
493 return 0;
494 }
495 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
496 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
497
498 return currentTimeMs;
499}
500
501static constexpr std::string_view getHostState(const PowerState state)
502{
503 switch (state)
504 {
505 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700506 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700507 case PowerState::gracefulTransitionToCycleOff:
508 return "xyz.openbmc_project.State.Host.HostState.Running";
509 break;
510 case PowerState::waitForPSPowerOK:
511 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700512 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700513 case PowerState::transitionToOff:
514 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700515 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700516 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700517 return "xyz.openbmc_project.State.Host.HostState.Off";
518 break;
519 default:
520 return "";
521 break;
522 }
523};
524static constexpr std::string_view getChassisState(const PowerState state)
525{
526 switch (state)
527 {
528 case PowerState::on:
529 case PowerState::transitionToOff:
530 case PowerState::gracefulTransitionToOff:
531 case PowerState::transitionToCycleOff:
532 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700533 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700534 return "xyz.openbmc_project.State.Chassis.PowerState.On";
535 break;
536 case PowerState::waitForPSPowerOK:
537 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700538 case PowerState::off:
539 case PowerState::cycleOff:
540 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
541 break;
542 default:
543 return "";
544 break;
545 }
546};
Naveen Moses117c34e2021-05-26 20:10:51 +0530547#ifdef CHASSIS_SYSTEM_RESET
548enum class SlotPowerState
549{
550 on,
551 off,
552};
553static SlotPowerState slotPowerState;
554static constexpr std::string_view getSlotState(const SlotPowerState state)
555{
556 switch (state)
557 {
558 case SlotPowerState::on:
559 return "xyz.openbmc_project.State.Chassis.PowerState.On";
560 break;
561 case SlotPowerState::off:
562 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
563 break;
564 default:
565 return "";
566 break;
567 }
568};
569static void setSlotPowerState(const SlotPowerState state)
570{
571 slotPowerState = state;
572 chassisSlotIface->set_property("CurrentPowerState",
573 std::string(getSlotState(slotPowerState)));
574 chassisSlotIface->set_property("LastStateChangeTime", getCurrentTimeMs());
575}
576#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700577static void savePowerState(const PowerState state)
578{
579 powerStateSaveTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -0700580 std::chrono::milliseconds(TimerMap["PowerOffSaveMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700581 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
582 if (ec)
583 {
584 // operation_aborted is expected if timer is canceled before
585 // completion.
586 if (ec != boost::asio::error::operation_aborted)
587 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800588 lg2::error("Power-state save async_wait failed: {ERROR_MSG}",
589 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700590 }
591 return;
592 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300593 appState.set(PersistentState::Params::PowerState,
594 std::string{getChassisState(state)});
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700595 });
596}
597static void setPowerState(const PowerState state)
598{
599 powerState = state;
600 logStateTransition(state);
601
602 hostIface->set_property("CurrentHostState",
603 std::string(getHostState(powerState)));
604
605 chassisIface->set_property("CurrentPowerState",
606 std::string(getChassisState(powerState)));
607 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
608
609 // Save the power state for the restore policy
610 savePowerState(state);
611}
612
613enum class RestartCause
614{
615 command,
616 resetButton,
617 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700618 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700619 powerPolicyOn,
620 powerPolicyRestore,
621 softReset,
622};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700623static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700624static std::string getRestartCause(RestartCause cause)
625{
626 switch (cause)
627 {
628 case RestartCause::command:
629 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
630 break;
631 case RestartCause::resetButton:
632 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
633 break;
634 case RestartCause::powerButton:
635 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
636 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700637 case RestartCause::watchdog:
638 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
639 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700640 case RestartCause::powerPolicyOn:
Jason M. Bills418ce112021-09-08 15:15:05 -0700641 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyAlwaysOn";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700642 break;
643 case RestartCause::powerPolicyRestore:
Jason M. Bills418ce112021-09-08 15:15:05 -0700644 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyPreviousState";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700645 break;
646 case RestartCause::softReset:
647 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
648 break;
649 default:
650 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
651 break;
652 }
653}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700654static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700655{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700656 // Add this to the set of causes for this restart
657 causeSet.insert(cause);
658}
659static void clearRestartCause()
660{
661 // Clear the set for the next restart
662 causeSet.clear();
663}
664static void setRestartCauseProperty(const std::string& cause)
665{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800666 lg2::info("RestartCause set to {RESTART_CAUSE}", "RESTART_CAUSE", cause);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700667 restartCauseIface->set_property("RestartCause", cause);
668}
Rashmi RV89f61312020-01-22 15:41:50 +0530669
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300670#ifdef USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +0530671static void resetACBootProperty()
672{
673 if ((causeSet.contains(RestartCause::command)) ||
674 (causeSet.contains(RestartCause::softReset)))
675 {
676 conn->async_method_call(
677 [](boost::system::error_code ec) {
678 if (ec)
679 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800680 lg2::error("failed to reset ACBoot property");
Rashmi RV89f61312020-01-22 15:41:50 +0530681 }
682 },
683 "xyz.openbmc_project.Settings",
684 "/xyz/openbmc_project/control/host0/ac_boot",
685 "org.freedesktop.DBus.Properties", "Set",
686 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
687 std::variant<std::string>{"False"});
688 }
689}
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300690#endif // USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +0530691
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700692static void setRestartCause()
693{
694 // Determine the actual restart cause based on the set of causes
695 std::string restartCause =
696 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
697 if (causeSet.contains(RestartCause::watchdog))
698 {
699 restartCause = getRestartCause(RestartCause::watchdog);
700 }
701 else if (causeSet.contains(RestartCause::command))
702 {
703 restartCause = getRestartCause(RestartCause::command);
704 }
705 else if (causeSet.contains(RestartCause::resetButton))
706 {
707 restartCause = getRestartCause(RestartCause::resetButton);
708 }
709 else if (causeSet.contains(RestartCause::powerButton))
710 {
711 restartCause = getRestartCause(RestartCause::powerButton);
712 }
713 else if (causeSet.contains(RestartCause::powerPolicyOn))
714 {
715 restartCause = getRestartCause(RestartCause::powerPolicyOn);
716 }
717 else if (causeSet.contains(RestartCause::powerPolicyRestore))
718 {
719 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
720 }
721 else if (causeSet.contains(RestartCause::softReset))
722 {
Matt Simmering58e379d2022-09-23 14:45:50 -0700723#if IGNORE_SOFT_RESETS_DURING_POST
724 if (ignoreNextSoftReset)
725 {
726 ignoreNextSoftReset = false;
727 return;
728 }
729#endif
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700730 restartCause = getRestartCause(RestartCause::softReset);
731 }
732
733 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700734}
735
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700736static void systemPowerGoodFailedLog()
737{
738 sd_journal_send(
739 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
740 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
741 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700742 TimerMap["SioPowerGoodWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700743}
744
745static void psPowerOKFailedLog()
746{
747 sd_journal_send(
748 "MESSAGE=PowerControl: power supply power good failed to assert",
749 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
750 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700751 TimerMap["PsPowerOKWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700752}
753
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700754static void powerRestorePolicyLog()
755{
756 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
757 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
758 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
759}
760
761static void powerButtonPressLog()
762{
763 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
764 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
765 "OpenBMC.0.1.PowerButtonPressed", NULL);
766}
767
768static void resetButtonPressLog()
769{
770 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
771 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
772 "OpenBMC.0.1.ResetButtonPressed", NULL);
773}
774
775static void nmiButtonPressLog()
776{
777 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
778 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
779 "OpenBMC.0.1.NMIButtonPressed", NULL);
780}
781
782static void nmiDiagIntLog()
783{
784 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
785 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
786 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
787}
788
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300789PersistentState::PersistentState()
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700790{
791 // create the power control directory if it doesn't exist
792 std::error_code ec;
793 if (!(std::filesystem::create_directories(powerControlDir, ec)))
794 {
795 if (ec.value() != 0)
796 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800797 lg2::error("failed to create {DIR_NAME}: {ERROR_MSG}", "DIR_NAME",
798 powerControlDir.string(), "ERROR_MSG", ec.message());
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300799 throw std::runtime_error("Failed to create state directory");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700800 }
801 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300802
803 // read saved state, it's ok, if the file doesn't exists
804 std::ifstream appStateStream(powerControlDir / stateFile);
805 if (!appStateStream.is_open())
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700806 {
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300807 lg2::info("Cannot open state file \'{PATH}\'", "PATH",
808 std::string(powerControlDir / stateFile));
809 stateData = nlohmann::json({});
810 return;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700811 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300812 try
813 {
814 appStateStream >> stateData;
815 if (stateData.is_discarded())
816 {
817 lg2::info("Cannot parse state file \'{PATH}\'", "PATH",
818 std::string(powerControlDir / stateFile));
819 stateData = nlohmann::json({});
820 return;
821 }
822 }
823 catch (const std::exception& ex)
824 {
825 lg2::info("Cannot read state file \'{PATH}\'", "PATH",
826 std::string(powerControlDir / stateFile));
827 stateData = nlohmann::json({});
828 return;
829 }
830}
831PersistentState::~PersistentState()
832{
833 saveState();
834}
835const std::string PersistentState::get(Params parameter)
836{
837 auto val = stateData.find(getName(parameter));
838 if (val != stateData.end())
839 {
840 return val->get<std::string>();
841 }
842 return getDefault(parameter);
843}
844void PersistentState::set(Params parameter, const std::string& value)
845{
846 stateData[getName(parameter)] = value;
847 saveState();
848}
849
850const std::string PersistentState::getName(const Params parameter)
851{
852 switch (parameter)
853 {
854 case Params::PowerState:
855 return "PowerState";
856 }
857 return "";
858}
859const std::string PersistentState::getDefault(const Params parameter)
860{
861 switch (parameter)
862 {
863 case Params::PowerState:
864 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
865 }
866 return "";
867}
868void PersistentState::saveState()
869{
870 std::ofstream appStateStream(powerControlDir / stateFile, std::ios::trunc);
871 if (!appStateStream.is_open())
872 {
873 lg2::error("Cannot write state file \'{PATH}\'", "PATH",
874 std::string(powerControlDir / stateFile));
875 return;
876 }
877 appStateStream << stateData.dump(indentationSize);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700878}
879
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300880static constexpr char const* setingsService = "xyz.openbmc_project.Settings";
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300881static constexpr char const* powerRestorePolicyIface =
882 "xyz.openbmc_project.Control.Power.RestorePolicy";
883#ifdef USE_ACBOOT
884static constexpr char const* powerACBootObject =
885 "/xyz/openbmc_project/control/host0/ac_boot";
886static constexpr char const* powerACBootIface =
887 "xyz.openbmc_project.Common.ACBoot";
888#endif // USE_ACBOOT
889
890namespace match_rules = sdbusplus::bus::match::rules;
891
892static int powerRestoreConfigHandler(sd_bus_message* m, void* context,
893 sd_bus_error*)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700894{
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300895 if (context == nullptr || m == nullptr)
896 {
897 throw std::runtime_error("Invalid match");
898 }
Patrick Williams439b9c32022-07-22 19:26:53 -0500899 sdbusplus::message_t message(m);
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300900 PowerRestoreController* powerRestore =
901 static_cast<PowerRestoreController*>(context);
902
903 if (std::string(message.get_member()) == "InterfacesAdded")
904 {
905 sdbusplus::message::object_path path;
906 boost::container::flat_map<std::string, dbusPropertiesList> data;
907
908 message.read(path, data);
909
910 for (auto& [iface, properties] : data)
911 {
912 if ((iface == powerRestorePolicyIface)
913#ifdef USE_ACBOOT
914 || (iface == powerACBootIface)
915#endif // USE_ACBOOT
916 )
917 {
918 powerRestore->setProperties(properties);
919 }
920 }
921 }
922 else if (std::string(message.get_member()) == "PropertiesChanged")
923 {
924 std::string interfaceName;
925 dbusPropertiesList propertiesChanged;
926
927 message.read(interfaceName, propertiesChanged);
928
929 powerRestore->setProperties(propertiesChanged);
930 }
931 return 1;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700932}
933
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300934void PowerRestoreController::run()
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700935{
Karthikeyan Pasupathib38fe832022-07-19 19:53:38 +0530936 std::string powerRestorePolicyObject =
937 "/xyz/openbmc_project/control/host" + node + "/power_restore_policy";
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300938 powerRestorePolicyLog();
939 // this list only needs to be created once
940 if (matches.empty())
941 {
942 matches.emplace_back(
943 *conn,
944 match_rules::interfacesAdded() +
945 match_rules::argNpath(0, powerRestorePolicyObject) +
946 match_rules::sender(setingsService),
947 powerRestoreConfigHandler, this);
948#ifdef USE_ACBOOT
949 matches.emplace_back(*conn,
950 match_rules::interfacesAdded() +
951 match_rules::argNpath(0, powerACBootObject) +
952 match_rules::sender(setingsService),
953 powerRestoreConfigHandler, this);
954 matches.emplace_back(*conn,
955 match_rules::propertiesChanged(powerACBootObject,
956 powerACBootIface) +
957 match_rules::sender(setingsService),
958 powerRestoreConfigHandler, this);
959#endif // USE_ACBOOT
960 }
961
962 // Check if it's already on DBus
963 conn->async_method_call(
964 [this](boost::system::error_code ec,
965 const dbusPropertiesList properties) {
966 if (ec)
967 {
968 return;
969 }
970 setProperties(properties);
971 },
972 setingsService, powerRestorePolicyObject,
973 "org.freedesktop.DBus.Properties", "GetAll", powerRestorePolicyIface);
974
975#ifdef USE_ACBOOT
976 // Check if it's already on DBus
977 conn->async_method_call(
978 [this](boost::system::error_code ec,
979 const dbusPropertiesList properties) {
980 if (ec)
981 {
982 return;
983 }
984 setProperties(properties);
985 },
986 setingsService, powerACBootObject, "org.freedesktop.DBus.Properties",
987 "GetAll", powerACBootIface);
988#endif
989}
990
991void PowerRestoreController::setProperties(const dbusPropertiesList& props)
992{
993 for (auto& [property, propValue] : props)
994 {
995 if (property == "PowerRestorePolicy")
996 {
997 const std::string* value = std::get_if<std::string>(&propValue);
998 if (value == nullptr)
999 {
1000 lg2::error("Unable to read Power Restore Policy");
1001 continue;
1002 }
1003 powerRestorePolicy = *value;
1004 }
1005 else if (property == "PowerRestoreDelay")
1006 {
1007 const uint64_t* value = std::get_if<uint64_t>(&propValue);
1008 if (value == nullptr)
1009 {
1010 lg2::error("Unable to read Power Restore Delay");
1011 continue;
1012 }
1013 powerRestoreDelay = *value / 1000000; // usec to sec
1014 }
1015#ifdef USE_ACBOOT
1016 else if (property == "ACBoot")
1017 {
1018 const std::string* value = std::get_if<std::string>(&propValue);
1019 if (value == nullptr)
1020 {
1021 lg2::error("Unable to read AC Boot status");
1022 continue;
1023 }
1024 acBoot = *value;
1025 }
1026#endif // USE_ACBOOT
1027 }
1028 invokeIfReady();
1029}
1030
1031void PowerRestoreController::invokeIfReady()
1032{
1033 if ((powerRestorePolicy.empty()) || (powerRestoreDelay < 0))
1034 {
1035 return;
1036 }
1037#ifdef USE_ACBOOT
1038 if (acBoot.empty() || acBoot == "Unknown")
1039 {
1040 return;
1041 }
1042#endif
1043
1044 matches.clear();
1045 if (!timerFired)
1046 {
1047 // Calculate the delay from now to meet the requested delay
1048 // Subtract the approximate uboot time
1049 static constexpr const int ubootSeconds = 20;
1050 int delay = powerRestoreDelay - ubootSeconds;
1051 // Subtract the time since boot
1052 struct sysinfo info = {};
1053 if (sysinfo(&info) == 0)
1054 {
1055 delay -= info.uptime;
1056 }
1057
1058 if (delay > 0)
1059 {
1060 powerRestoreTimer.expires_after(std::chrono::seconds(delay));
1061 lg2::info("Power Restore delay of {DELAY} seconds started", "DELAY",
1062 delay);
1063 powerRestoreTimer.async_wait([this](const boost::system::error_code
1064 ec) {
1065 if (ec)
1066 {
1067 // operation_aborted is expected if timer is canceled before
1068 // completion.
1069 if (ec == boost::asio::error::operation_aborted)
1070 {
1071 return;
1072 }
1073 lg2::error(
1074 "power restore policy async_wait failed: {ERROR_MSG}",
1075 "ERROR_MSG", ec.message());
1076 }
1077 else
1078 {
1079 lg2::info("Power Restore delay timer expired");
1080 }
1081 invoke();
1082 });
1083 timerFired = true;
1084 }
1085 else
1086 {
1087 invoke();
1088 }
1089 }
1090}
1091
1092void PowerRestoreController::invoke()
1093{
1094 // we want to run Power Restore only once
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001095 if (policyInvoked)
1096 {
1097 return;
1098 }
1099 policyInvoked = true;
1100
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001101 lg2::info("Invoking Power Restore Policy {POLICY}", "POLICY",
1102 powerRestorePolicy);
1103 if (powerRestorePolicy ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001104 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
1105 {
1106 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001107 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001108 }
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001109 else if (powerRestorePolicy ==
Jason M. Bills418ce112021-09-08 15:15:05 -07001110 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore")
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001111 {
1112 if (wasPowerDropped())
1113 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001114 lg2::info("Power was dropped, restoring Host On state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001115 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001116 setRestartCauseProperty(
1117 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001118 }
1119 else
1120 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001121 lg2::info("No power drop, restoring Host Off state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001122 }
1123 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -07001124 // We're done with the previous power state for the restore policy, so store
1125 // the current state
1126 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001127}
1128
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001129bool PowerRestoreController::wasPowerDropped()
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001130{
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001131 std::string state = appState.get(PersistentState::Params::PowerState);
1132 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001133}
1134
Zev Weiss676ef2c2021-09-02 21:54:02 -05001135static void waitForGPIOEvent(const std::string& name,
1136 const std::function<void(bool)>& eventHandler,
1137 gpiod::line& line,
1138 boost::asio::posix::stream_descriptor& event)
1139{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001140 event.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1141 [&name, eventHandler, &line,
1142 &event](const boost::system::error_code ec) {
1143 if (ec)
1144 {
1145 lg2::error(
1146 "{GPIO_NAME} fd handler error: {ERROR_MSG}",
1147 "GPIO_NAME", name, "ERROR_MSG", ec.message());
1148 // TODO: throw here to force power-control to
1149 // restart?
1150 return;
1151 }
1152 gpiod::line_event line_event = line.event_read();
1153 eventHandler(line_event.event_type ==
1154 gpiod::line_event::RISING_EDGE);
1155 waitForGPIOEvent(name, eventHandler, line, event);
1156 });
Zev Weiss676ef2c2021-09-02 21:54:02 -05001157}
1158
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001159static bool requestGPIOEvents(
Zev Weiss676ef2c2021-09-02 21:54:02 -05001160 const std::string& name, const std::function<void(bool)>& handler,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001161 gpiod::line& gpioLine,
1162 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
1163{
1164 // Find the GPIO line
1165 gpioLine = gpiod::find_line(name);
1166 if (!gpioLine)
1167 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001168 lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001169 return false;
1170 }
1171
1172 try
1173 {
Andrei Kartashev3efcf372021-12-29 15:32:17 +03001174 gpioLine.request({appName, gpiod::line_request::EVENT_BOTH_EDGES, {}});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001175 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001176 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001177 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001178 lg2::error("Failed to request events for {GPIO_NAME}: {ERROR}",
1179 "GPIO_NAME", name, "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001180 return false;
1181 }
1182
1183 int gpioLineFd = gpioLine.event_get_fd();
1184 if (gpioLineFd < 0)
1185 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001186 lg2::error("Failed to get {GPIO_NAME} fd", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001187 return false;
1188 }
1189
1190 gpioEventDescriptor.assign(gpioLineFd);
1191
Zev Weiss676ef2c2021-09-02 21:54:02 -05001192 waitForGPIOEvent(name, handler, gpioLine, gpioEventDescriptor);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001193 return true;
1194}
1195
1196static bool setGPIOOutput(const std::string& name, const int value,
1197 gpiod::line& gpioLine)
1198{
1199 // Find the GPIO line
1200 gpioLine = gpiod::find_line(name);
1201 if (!gpioLine)
1202 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001203 lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001204 return false;
1205 }
1206
1207 // Request GPIO output to specified value
1208 try
1209 {
Andrei Kartashev3efcf372021-12-29 15:32:17 +03001210 gpioLine.request({appName, gpiod::line_request::DIRECTION_OUTPUT, {}},
1211 value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001212 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001213 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001214 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001215 lg2::error("Failed to request {GPIO_NAME} output: {ERROR}", "GPIO_NAME",
1216 name, "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001217 return false;
1218 }
1219
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001220 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1221 "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001222 return true;
1223}
1224
1225static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1226 const std::string& name, const int value,
1227 const int durationMs)
1228{
1229 // Set the masked GPIO line to the specified value
1230 maskedGPIOLine.set_value(value);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001231 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1232 "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001233 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001234 gpioAssertTimer.async_wait(
1235 [maskedGPIOLine, value, name](const boost::system::error_code ec) {
1236 // Set the masked GPIO line back to the opposite value
1237 maskedGPIOLine.set_value(!value);
1238 lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
1239 if (ec)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001240 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001241 // operation_aborted is expected if timer is canceled before
1242 // completion.
1243 if (ec != boost::asio::error::operation_aborted)
1244 {
1245 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1246 "GPIO_NAME", name, "ERROR_MSG", ec.message());
1247 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001248 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001249 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001250 return 0;
1251}
1252
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001253static int setGPIOOutputForMs(const ConfigData& config, const int value,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001254 const int durationMs)
1255{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001256 // If the requested GPIO is masked, use the mask line to set the output
1257 if (powerButtonMask && config.lineName == powerOutConfig.lineName)
1258 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001259 return setMaskedGPIOOutputForMs(powerButtonMask, config.lineName, value,
1260 durationMs);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001261 }
1262 if (resetButtonMask && config.lineName == resetOutConfig.lineName)
1263 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001264 return setMaskedGPIOOutputForMs(resetButtonMask, config.lineName, value,
1265 durationMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001266 }
1267
1268 // No mask set, so request and set the GPIO normally
1269 gpiod::line gpioLine;
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001270 if (!setGPIOOutput(config.lineName, value, gpioLine))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001271 {
1272 return -1;
1273 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001274 const std::string name = config.lineName;
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001275
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001276 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001277 gpioAssertTimer.async_wait(
1278 [gpioLine, value, name](const boost::system::error_code ec) {
1279 // Set the GPIO line back to the opposite value
1280 gpioLine.set_value(!value);
1281 lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
1282 if (ec)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001283 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001284 // operation_aborted is expected if timer is canceled before
1285 // completion.
1286 if (ec != boost::asio::error::operation_aborted)
1287 {
1288 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1289 "GPIO_NAME", name, "ERROR_MSG", ec.message());
1290 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001291 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001292 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001293 return 0;
1294}
1295
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001296static int assertGPIOForMs(const ConfigData& config, const int durationMs)
1297{
1298 return setGPIOOutputForMs(config, config.polarity, durationMs);
1299}
1300
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001301static void powerOn()
1302{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001303 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001304}
Naveen Moses117c34e2021-05-26 20:10:51 +05301305#ifdef CHASSIS_SYSTEM_RESET
1306static int slotPowerOn()
1307{
1308 if (power_control::slotPowerState != power_control::SlotPowerState::on)
1309 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001310
Naveen Moses117c34e2021-05-26 20:10:51 +05301311 slotPowerLine.set_value(1);
1312
1313 if (slotPowerLine.get_value() > 0)
1314 {
1315 setSlotPowerState(SlotPowerState::on);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001316 lg2::info("Slot Power is switched On\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301317 }
1318 else
1319 {
1320 return -1;
1321 }
1322 }
1323 else
1324 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001325 lg2::info("Slot Power is already in 'On' state\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301326 return -1;
1327 }
1328 return 0;
1329}
1330static int slotPowerOff()
1331{
1332 if (power_control::slotPowerState != power_control::SlotPowerState::off)
1333 {
1334 slotPowerLine.set_value(0);
1335
1336 if (!(slotPowerLine.get_value() > 0))
1337 {
1338 setSlotPowerState(SlotPowerState::off);
1339 setPowerState(PowerState::off);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001340 lg2::info("Slot Power is switched Off\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301341 }
1342 else
1343 {
1344 return -1;
1345 }
1346 }
1347 else
1348 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001349 lg2::info("Slot Power is already in 'Off' state\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301350 return -1;
1351 }
1352 return 0;
1353}
1354static void slotPowerCycle()
1355{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001356 lg2::info("Slot Power Cycle started\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301357 slotPowerOff();
1358 slotPowerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001359 std::chrono::milliseconds(TimerMap["SlotPowerCycleMs"]));
Naveen Moses117c34e2021-05-26 20:10:51 +05301360 slotPowerCycleTimer.async_wait([](const boost::system::error_code ec) {
1361 if (ec)
1362 {
1363 if (ec != boost::asio::error::operation_aborted)
1364 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001365 lg2::error(
1366 "Slot Power cycle timer async_wait failed: {ERROR_MSG}",
1367 "ERROR_MSG", ec.message());
Naveen Moses117c34e2021-05-26 20:10:51 +05301368 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001369 lg2::info("Slot Power cycle timer canceled\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301370 return;
1371 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001372 lg2::info("Slot Power cycle timer completed\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301373 slotPowerOn();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001374 lg2::info("Slot Power Cycle Completed\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301375 });
1376}
1377#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001378static void gracefulPowerOff()
1379{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001380 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001381}
1382
1383static void forcePowerOff()
1384{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001385 if (assertGPIOForMs(powerOutConfig, TimerMap["ForceOffPulseMs"]) < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001386 {
1387 return;
1388 }
1389
Jason M. Billsc6961b62021-10-21 14:08:02 -07001390 // If the force off timer expires, then the power-button override failed
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001391 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1392 if (ec)
1393 {
1394 // operation_aborted is expected if timer is canceled before
1395 // completion.
1396 if (ec != boost::asio::error::operation_aborted)
1397 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001398 lg2::error("Force power off async_wait failed: {ERROR_MSG}",
1399 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001400 }
1401 return;
1402 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001403
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001404 lg2::error("Power-button override failed. Not sure what to do now.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001405 });
1406}
1407
1408static void reset()
1409{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001410 assertGPIOForMs(resetOutConfig, TimerMap["ResetPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001411}
1412
1413static void gracefulPowerOffTimerStart()
1414{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001415 lg2::info("Graceful power-off timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001416 gracefulPowerOffTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001417 std::chrono::seconds(TimerMap["GracefulPowerOffS"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001418 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1419 if (ec)
1420 {
1421 // operation_aborted is expected if timer is canceled before
1422 // completion.
1423 if (ec != boost::asio::error::operation_aborted)
1424 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001425 lg2::error("Graceful power-off async_wait failed: {ERROR_MSG}",
1426 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001427 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001428 lg2::info("Graceful power-off timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001429 return;
1430 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001431 lg2::info("Graceful power-off timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001432 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1433 });
1434}
1435
1436static void powerCycleTimerStart()
1437{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001438 lg2::info("Power-cycle timer started");
Priyatharshan P70120512020-09-16 18:47:20 +05301439 powerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001440 std::chrono::milliseconds(TimerMap["PowerCycleMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001441 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1442 if (ec)
1443 {
1444 // operation_aborted is expected if timer is canceled before
1445 // completion.
1446 if (ec != boost::asio::error::operation_aborted)
1447 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001448 lg2::error("Power-cycle async_wait failed: {ERROR_MSG}",
1449 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001450 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001451 lg2::info("Power-cycle timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001452 return;
1453 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001454 lg2::info("Power-cycle timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001455 sendPowerControlEvent(Event::powerCycleTimerExpired);
1456 });
1457}
1458
1459static void psPowerOKWatchdogTimerStart()
1460{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001461 lg2::info("power supply power OK watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001462 psPowerOKWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001463 std::chrono::milliseconds(TimerMap["PsPowerOKWatchdogMs"]));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001464 psPowerOKWatchdogTimer.async_wait([](const boost::system::error_code ec) {
1465 if (ec)
1466 {
1467 // operation_aborted is expected if timer is canceled before
1468 // completion.
1469 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001470 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001471 lg2::error(
1472 "power supply power OK watchdog async_wait failed: {ERROR_MSG}",
1473 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001474 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001475 lg2::info("power supply power OK watchdog timer canceled");
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001476 return;
1477 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001478 lg2::info("power supply power OK watchdog timer expired");
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001479 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1480 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001481}
1482
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001483static void warmResetCheckTimerStart()
1484{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001485 lg2::info("Warm reset check timer started");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001486 warmResetCheckTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001487 std::chrono::milliseconds(TimerMap["WarmResetCheckMs"]));
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001488 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1489 if (ec)
1490 {
1491 // operation_aborted is expected if timer is canceled before
1492 // completion.
1493 if (ec != boost::asio::error::operation_aborted)
1494 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001495 lg2::error("Warm reset check async_wait failed: {ERROR_MSG}",
1496 "ERROR_MSG", ec.message());
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001497 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001498 lg2::info("Warm reset check timer canceled");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001499 return;
1500 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001501 lg2::info("Warm reset check timer completed");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001502 sendPowerControlEvent(Event::warmResetDetected);
1503 });
1504}
1505
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001506static void pohCounterTimerStart()
1507{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001508 lg2::info("POH timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001509 // Set the time-out as 1 hour, to align with POH command in ipmid
1510 pohCounterTimer.expires_after(std::chrono::hours(1));
1511 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1512 if (ec)
1513 {
1514 // operation_aborted is expected if timer is canceled before
1515 // completion.
1516 if (ec != boost::asio::error::operation_aborted)
1517 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001518 lg2::error("POH timer async_wait failed: {ERROR_MSG}",
1519 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001520 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001521 lg2::info("POH timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001522 return;
1523 }
1524
1525 if (getHostState(powerState) !=
1526 "xyz.openbmc_project.State.Host.HostState.Running")
1527 {
1528 return;
1529 }
1530
1531 conn->async_method_call(
1532 [](boost::system::error_code ec,
1533 const std::variant<uint32_t>& pohCounterProperty) {
1534 if (ec)
1535 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001536 lg2::error("error getting poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001537 return;
1538 }
1539 const uint32_t* pohCounter =
1540 std::get_if<uint32_t>(&pohCounterProperty);
1541 if (pohCounter == nullptr)
1542 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001543 lg2::error("unable to read poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001544 return;
1545 }
1546
1547 conn->async_method_call(
1548 [](boost::system::error_code ec) {
1549 if (ec)
1550 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001551 lg2::error("failed to set poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001552 }
1553 },
1554 "xyz.openbmc_project.Settings",
1555 "/xyz/openbmc_project/state/chassis0",
1556 "org.freedesktop.DBus.Properties", "Set",
1557 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1558 std::variant<uint32_t>(*pohCounter + 1));
1559 },
1560 "xyz.openbmc_project.Settings",
1561 "/xyz/openbmc_project/state/chassis0",
1562 "org.freedesktop.DBus.Properties", "Get",
1563 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1564
1565 pohCounterTimerStart();
1566 });
1567}
1568
1569static void currentHostStateMonitor()
1570{
Yong Li8d660212019-12-27 10:18:10 +08001571 if (getHostState(powerState) ==
1572 "xyz.openbmc_project.State.Host.HostState.Running")
1573 {
1574 pohCounterTimerStart();
1575 // Clear the restart cause set for the next restart
1576 clearRestartCause();
1577 }
1578 else
1579 {
1580 pohCounterTimer.cancel();
1581 // Set the restart cause set for this restart
1582 setRestartCause();
1583 }
1584
Patrick Williams439b9c32022-07-22 19:26:53 -05001585 static auto match = sdbusplus::bus::match_t(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001586 *conn,
1587 "type='signal',member='PropertiesChanged', "
1588 "interface='org.freedesktop.DBus.Properties', "
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001589 "arg0='xyz.openbmc_project.State.Host'",
Patrick Williams439b9c32022-07-22 19:26:53 -05001590 [](sdbusplus::message_t& message) {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001591 std::string intfName;
1592 std::map<std::string, std::variant<std::string>> properties;
1593
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001594 try
1595 {
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001596 message.read(intfName, properties);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001597 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05001598 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001599 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001600 lg2::error("Unable to read host state: {ERROR}", "ERROR", e);
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001601 return;
1602 }
1603 if (properties.empty())
1604 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001605 lg2::error("ERROR: Empty PropertiesChanged signal received");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001606 return;
1607 }
1608
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001609 // We only want to check for CurrentHostState
1610 if (properties.begin()->first != "CurrentHostState")
1611 {
1612 return;
1613 }
1614 std::string* currentHostState =
1615 std::get_if<std::string>(&(properties.begin()->second));
1616 if (currentHostState == nullptr)
1617 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001618 lg2::error("{PROPERTY} property invalid", "PROPERTY",
1619 properties.begin()->first);
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001620 return;
1621 }
1622
1623 if (*currentHostState ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001624 "xyz.openbmc_project.State.Host.HostState.Running")
1625 {
1626 pohCounterTimerStart();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001627 // Clear the restart cause set for the next restart
1628 clearRestartCause();
Yong Li8d660212019-12-27 10:18:10 +08001629 sd_journal_send("MESSAGE=Host system DC power is on",
1630 "PRIORITY=%i", LOG_INFO,
1631 "REDFISH_MESSAGE_ID=%s",
1632 "OpenBMC.0.1.DCPowerOn", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001633 }
1634 else
1635 {
1636 pohCounterTimer.cancel();
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301637 // POST_COMPLETE GPIO event is not working in some platforms
1638 // when power state is changed to OFF. This resulted in
1639 // 'OperatingSystemState' to stay at 'Standby', even though
1640 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1641 // if HostState is trurned to OFF.
Tim Lee86239182021-12-23 11:46:01 +08001642 setOperatingSystemState(OperatingSystemStateStage::Inactive);
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301643
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001644 // Set the restart cause set for this restart
1645 setRestartCause();
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001646#ifdef USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +05301647 resetACBootProperty();
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001648#endif // USE_ACBOOT
Yong Li8d660212019-12-27 10:18:10 +08001649 sd_journal_send("MESSAGE=Host system DC power is off",
1650 "PRIORITY=%i", LOG_INFO,
1651 "REDFISH_MESSAGE_ID=%s",
1652 "OpenBMC.0.1.DCPowerOff", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001653 }
1654 });
1655}
1656
1657static void sioPowerGoodWatchdogTimerStart()
1658{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001659 lg2::info("SIO power good watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001660 sioPowerGoodWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001661 std::chrono::milliseconds(TimerMap["SioPowerGoodWatchdogMs"]));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001662 sioPowerGoodWatchdogTimer.async_wait([](const boost::system::error_code
1663 ec) {
1664 if (ec)
1665 {
1666 // operation_aborted is expected if timer is canceled before
1667 // completion.
1668 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001669 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001670 lg2::error(
1671 "SIO power good watchdog async_wait failed: {ERROR_MSG}",
1672 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001673 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001674 lg2::info("SIO power good watchdog timer canceled");
1675 return;
1676 }
1677 lg2::info("SIO power good watchdog timer completed");
1678 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1679 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001680}
1681
1682static void powerStateOn(const Event event)
1683{
1684 logEvent(__FUNCTION__, event);
1685 switch (event)
1686 {
1687 case Event::psPowerOKDeAssert:
1688 setPowerState(PowerState::off);
1689 // DC power is unexpectedly lost, beep
1690 beep(beepPowerFail);
1691 break;
1692 case Event::sioS5Assert:
1693 setPowerState(PowerState::transitionToOff);
Matt Simmering58e379d2022-09-23 14:45:50 -07001694#if IGNORE_SOFT_RESETS_DURING_POST
1695 // Only recognize soft resets once host gets past POST COMPLETE
1696 if (operatingSystemState != OperatingSystemStateStage::Standby)
1697 {
1698 ignoreNextSoftReset = true;
1699 }
1700#endif
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001701 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001702 break;
Jason M. Billsfb957332021-01-28 13:18:46 -08001703#if USE_PLT_RST
1704 case Event::pltRstAssert:
1705#else
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001706 case Event::postCompleteDeAssert:
Jason M. Billsfb957332021-01-28 13:18:46 -08001707#endif
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001708 setPowerState(PowerState::checkForWarmReset);
Matt Simmering58e379d2022-09-23 14:45:50 -07001709#if IGNORE_SOFT_RESETS_DURING_POST
1710 // Only recognize soft resets once host gets past POST COMPLETE
1711 if (operatingSystemState != OperatingSystemStateStage::Standby)
1712 {
1713 ignoreNextSoftReset = true;
1714 }
1715#endif
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001716 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001717 warmResetCheckTimerStart();
1718 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001719 case Event::powerButtonPressed:
1720 setPowerState(PowerState::gracefulTransitionToOff);
1721 gracefulPowerOffTimerStart();
1722 break;
1723 case Event::powerOffRequest:
1724 setPowerState(PowerState::transitionToOff);
1725 forcePowerOff();
1726 break;
1727 case Event::gracefulPowerOffRequest:
1728 setPowerState(PowerState::gracefulTransitionToOff);
1729 gracefulPowerOffTimerStart();
1730 gracefulPowerOff();
1731 break;
1732 case Event::powerCycleRequest:
1733 setPowerState(PowerState::transitionToCycleOff);
1734 forcePowerOff();
1735 break;
1736 case Event::gracefulPowerCycleRequest:
1737 setPowerState(PowerState::gracefulTransitionToCycleOff);
1738 gracefulPowerOffTimerStart();
1739 gracefulPowerOff();
1740 break;
1741 case Event::resetRequest:
1742 reset();
1743 break;
1744 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001745 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001746 break;
1747 }
1748}
1749
1750static void powerStateWaitForPSPowerOK(const Event event)
1751{
1752 logEvent(__FUNCTION__, event);
1753 switch (event)
1754 {
1755 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301756 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001757 // Cancel any GPIO assertions held during the transition
1758 gpioAssertTimer.cancel();
1759 psPowerOKWatchdogTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301760 if (sioEnabled == true)
1761 {
1762 sioPowerGoodWatchdogTimerStart();
1763 setPowerState(PowerState::waitForSIOPowerGood);
1764 }
1765 else
1766 {
1767 setPowerState(PowerState::on);
1768 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001769 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301770 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001771 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001772 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001773 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001774 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001775 case Event::sioPowerGoodAssert:
1776 psPowerOKWatchdogTimer.cancel();
1777 setPowerState(PowerState::on);
1778 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001779 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001780 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001781 break;
1782 }
1783}
1784
1785static void powerStateWaitForSIOPowerGood(const Event event)
1786{
1787 logEvent(__FUNCTION__, event);
1788 switch (event)
1789 {
1790 case Event::sioPowerGoodAssert:
1791 sioPowerGoodWatchdogTimer.cancel();
1792 setPowerState(PowerState::on);
1793 break;
1794 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001795 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001796 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001797 break;
1798 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001799 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001800 break;
1801 }
1802}
1803
1804static void powerStateOff(const Event event)
1805{
1806 logEvent(__FUNCTION__, event);
1807 switch (event)
1808 {
1809 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301810 {
1811 if (sioEnabled == true)
1812 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001813 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301814 setPowerState(PowerState::waitForSIOPowerGood);
1815 }
1816 else
1817 {
1818 setPowerState(PowerState::on);
1819 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001820 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301821 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001822 case Event::sioS5DeAssert:
Jason M. Billsfe159032022-09-01 16:03:37 -07001823 psPowerOKWatchdogTimerStart();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001824 setPowerState(PowerState::waitForPSPowerOK);
1825 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001826 case Event::sioPowerGoodAssert:
1827 setPowerState(PowerState::on);
1828 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001829 case Event::powerButtonPressed:
1830 psPowerOKWatchdogTimerStart();
1831 setPowerState(PowerState::waitForPSPowerOK);
1832 break;
1833 case Event::powerOnRequest:
1834 psPowerOKWatchdogTimerStart();
1835 setPowerState(PowerState::waitForPSPowerOK);
1836 powerOn();
1837 break;
1838 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001839 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001840 break;
1841 }
1842}
1843
1844static void powerStateTransitionToOff(const Event event)
1845{
1846 logEvent(__FUNCTION__, event);
1847 switch (event)
1848 {
1849 case Event::psPowerOKDeAssert:
1850 // Cancel any GPIO assertions held during the transition
1851 gpioAssertTimer.cancel();
1852 setPowerState(PowerState::off);
1853 break;
1854 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001855 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001856 break;
1857 }
1858}
1859
1860static void powerStateGracefulTransitionToOff(const Event event)
1861{
1862 logEvent(__FUNCTION__, event);
1863 switch (event)
1864 {
1865 case Event::psPowerOKDeAssert:
1866 gracefulPowerOffTimer.cancel();
1867 setPowerState(PowerState::off);
1868 break;
1869 case Event::gracefulPowerOffTimerExpired:
1870 setPowerState(PowerState::on);
1871 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001872 case Event::powerOffRequest:
1873 gracefulPowerOffTimer.cancel();
1874 setPowerState(PowerState::transitionToOff);
1875 forcePowerOff();
1876 break;
1877 case Event::powerCycleRequest:
1878 gracefulPowerOffTimer.cancel();
1879 setPowerState(PowerState::transitionToCycleOff);
1880 forcePowerOff();
1881 break;
1882 case Event::resetRequest:
1883 gracefulPowerOffTimer.cancel();
1884 setPowerState(PowerState::on);
1885 reset();
1886 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001887 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001888 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001889 break;
1890 }
1891}
1892
1893static void powerStateCycleOff(const Event event)
1894{
1895 logEvent(__FUNCTION__, event);
1896 switch (event)
1897 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001898 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301899 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001900 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301901 if (sioEnabled == true)
1902 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001903 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301904 setPowerState(PowerState::waitForSIOPowerGood);
1905 }
1906 else
1907 {
1908 setPowerState(PowerState::on);
1909 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001910 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301911 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001912 case Event::sioS5DeAssert:
1913 powerCycleTimer.cancel();
Jason M. Billsfe159032022-09-01 16:03:37 -07001914 psPowerOKWatchdogTimerStart();
Jason M. Bills35aa6652020-04-30 16:24:55 -07001915 setPowerState(PowerState::waitForPSPowerOK);
1916 break;
1917 case Event::powerButtonPressed:
1918 powerCycleTimer.cancel();
1919 psPowerOKWatchdogTimerStart();
1920 setPowerState(PowerState::waitForPSPowerOK);
1921 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001922 case Event::powerCycleTimerExpired:
1923 psPowerOKWatchdogTimerStart();
1924 setPowerState(PowerState::waitForPSPowerOK);
1925 powerOn();
1926 break;
1927 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001928 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001929 break;
1930 }
1931}
1932
1933static void powerStateTransitionToCycleOff(const Event event)
1934{
1935 logEvent(__FUNCTION__, event);
1936 switch (event)
1937 {
1938 case Event::psPowerOKDeAssert:
1939 // Cancel any GPIO assertions held during the transition
1940 gpioAssertTimer.cancel();
1941 setPowerState(PowerState::cycleOff);
1942 powerCycleTimerStart();
1943 break;
1944 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001945 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001946 break;
1947 }
1948}
1949
1950static void powerStateGracefulTransitionToCycleOff(const Event event)
1951{
1952 logEvent(__FUNCTION__, event);
1953 switch (event)
1954 {
1955 case Event::psPowerOKDeAssert:
1956 gracefulPowerOffTimer.cancel();
1957 setPowerState(PowerState::cycleOff);
1958 powerCycleTimerStart();
1959 break;
1960 case Event::gracefulPowerOffTimerExpired:
1961 setPowerState(PowerState::on);
1962 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001963 case Event::powerOffRequest:
1964 gracefulPowerOffTimer.cancel();
1965 setPowerState(PowerState::transitionToOff);
1966 forcePowerOff();
1967 break;
1968 case Event::powerCycleRequest:
1969 gracefulPowerOffTimer.cancel();
1970 setPowerState(PowerState::transitionToCycleOff);
1971 forcePowerOff();
1972 break;
1973 case Event::resetRequest:
1974 gracefulPowerOffTimer.cancel();
1975 setPowerState(PowerState::on);
1976 reset();
1977 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001978 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001979 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001980 break;
1981 }
1982}
1983
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001984static void powerStateCheckForWarmReset(const Event event)
1985{
1986 logEvent(__FUNCTION__, event);
1987 switch (event)
1988 {
1989 case Event::sioS5Assert:
1990 warmResetCheckTimer.cancel();
1991 setPowerState(PowerState::transitionToOff);
1992 break;
1993 case Event::warmResetDetected:
1994 setPowerState(PowerState::on);
1995 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001996 case Event::psPowerOKDeAssert:
1997 warmResetCheckTimer.cancel();
1998 setPowerState(PowerState::off);
1999 // DC power is unexpectedly lost, beep
2000 beep(beepPowerFail);
2001 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002002 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002003 lg2::info("No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002004 break;
2005 }
2006}
2007
Zev Weiss584aa132021-09-02 19:21:52 -05002008static void psPowerOKHandler(bool state)
2009{
2010 Event powerControlEvent =
2011 state ? Event::psPowerOKAssert : Event::psPowerOKDeAssert;
2012 sendPowerControlEvent(powerControlEvent);
2013}
2014
Zev Weiss584aa132021-09-02 19:21:52 -05002015static void sioPowerGoodHandler(bool state)
2016{
2017 Event powerControlEvent =
2018 state ? Event::sioPowerGoodAssert : Event::sioPowerGoodDeAssert;
2019 sendPowerControlEvent(powerControlEvent);
2020}
2021
Zev Weiss584aa132021-09-02 19:21:52 -05002022static void sioOnControlHandler(bool state)
2023{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002024 lg2::info("SIO_ONCONTROL value changed: {VALUE}", "VALUE",
2025 static_cast<int>(state));
Zev Weiss584aa132021-09-02 19:21:52 -05002026}
2027
Zev Weiss584aa132021-09-02 19:21:52 -05002028static void sioS5Handler(bool state)
2029{
2030 Event powerControlEvent = state ? Event::sioS5DeAssert : Event::sioS5Assert;
2031 sendPowerControlEvent(powerControlEvent);
2032}
2033
Zev Weiss584aa132021-09-02 19:21:52 -05002034static void powerButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002035{
Zev Weiss584aa132021-09-02 19:21:52 -05002036 powerButtonIface->set_property("ButtonPressed", !state);
2037 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002038 {
2039 powerButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002040 if (!powerButtonMask)
2041 {
2042 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002043 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002044 }
2045 else
2046 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002047 lg2::info("power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002048 }
2049 }
Zev Weiss584aa132021-09-02 19:21:52 -05002050}
2051
Zev Weiss584aa132021-09-02 19:21:52 -05002052static void resetButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002053{
Zev Weiss584aa132021-09-02 19:21:52 -05002054 resetButtonIface->set_property("ButtonPressed", !state);
2055 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002056 {
2057 resetButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002058 if (!resetButtonMask)
2059 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002060 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002061 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002062 }
2063 else
2064 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002065 lg2::info("reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002066 }
2067 }
Zev Weiss584aa132021-09-02 19:21:52 -05002068}
2069
Vijay Khemka04175c22020-10-09 14:28:11 -07002070#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002071static constexpr auto systemdBusname = "org.freedesktop.systemd1";
2072static constexpr auto systemdPath = "/org/freedesktop/systemd1";
2073static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
2074static constexpr auto systemTargetName = "chassis-system-reset.target";
2075
2076void systemReset()
2077{
2078 conn->async_method_call(
2079 [](boost::system::error_code ec) {
2080 if (ec)
2081 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002082 lg2::error("Failed to call chassis system reset: {ERR}", "ERR",
2083 ec.message());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002084 }
2085 },
2086 systemdBusname, systemdPath, systemdInterface, "StartUnit",
2087 systemTargetName, "replace");
2088}
Vijay Khemka04175c22020-10-09 14:28:11 -07002089#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002090
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002091static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002092{
2093 conn->async_method_call(
2094 [](boost::system::error_code ec) {
2095 if (ec)
2096 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002097 lg2::error("failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002098 }
2099 },
Chen Yugang303bd582019-11-01 08:45:06 +08002100 "xyz.openbmc_project.Settings",
2101 "/xyz/openbmc_project/Chassis/Control/NMISource",
2102 "org.freedesktop.DBus.Properties", "Set",
2103 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
2104 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002105}
2106
2107static void nmiReset(void)
2108{
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002109 const static constexpr int nmiOutPulseTimeMs = 200;
2110
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002111 lg2::info("NMI out action");
Jian Zhang461a1662022-09-22 11:29:01 +08002112 nmiOutLine.set_value(nmiOutConfig.polarity);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002113 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME",
Jian Zhang461a1662022-09-22 11:29:01 +08002114 nmiOutConfig.lineName, "GPIO_VALUE", nmiOutConfig.polarity);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002115 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2116 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2117 // restore the NMI_OUT GPIO line back to the opposite value
Jian Zhang461a1662022-09-22 11:29:01 +08002118 nmiOutLine.set_value(!nmiOutConfig.polarity);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002119 lg2::info("{GPIO_NAME} released", "GPIO_NAME", nmiOutConfig.lineName);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002120 if (ec)
2121 {
2122 // operation_aborted is expected if timer is canceled before
2123 // completion.
2124 if (ec != boost::asio::error::operation_aborted)
2125 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002126 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
2127 "GPIO_NAME", nmiOutConfig.lineName, "ERROR_MSG",
2128 ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002129 }
2130 }
2131 });
2132 // log to redfish
2133 nmiDiagIntLog();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002134 lg2::info("NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002135 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002136 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002137}
2138
2139static void nmiSourcePropertyMonitor(void)
2140{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002141 lg2::info("NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002142
Patrick Williams439b9c32022-07-22 19:26:53 -05002143 static std::unique_ptr<sdbusplus::bus::match_t> nmiSourceMatch =
2144 std::make_unique<sdbusplus::bus::match_t>(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002145 *conn,
2146 "type='signal',interface='org.freedesktop.DBus.Properties',"
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002147 "member='PropertiesChanged',"
2148 "arg0namespace='xyz.openbmc_project.Chassis.Control.NMISource'",
Patrick Williams439b9c32022-07-22 19:26:53 -05002149 [](sdbusplus::message_t& msg) {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002150 std::string interfaceName;
2151 boost::container::flat_map<std::string,
2152 std::variant<bool, std::string>>
2153 propertiesChanged;
2154 std::string state;
2155 bool value = true;
2156 try
2157 {
2158 msg.read(interfaceName, propertiesChanged);
2159 if (propertiesChanged.begin()->first == "Enabled")
2160 {
2161 value =
2162 std::get<bool>(propertiesChanged.begin()->second);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002163 lg2::info(
2164 "NMI Enabled propertiesChanged value: {VALUE}",
2165 "VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002166 nmiEnabled = value;
2167 if (nmiEnabled)
2168 {
2169 nmiReset();
2170 }
2171 }
2172 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002173 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002174 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002175 lg2::error("Unable to read NMI source: {ERROR}", "ERROR",
2176 e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002177 return;
2178 }
2179 });
2180}
2181
2182static void setNmiSource()
2183{
2184 conn->async_method_call(
2185 [](boost::system::error_code ec) {
2186 if (ec)
2187 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002188 lg2::error("failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002189 }
2190 },
Chen Yugang303bd582019-11-01 08:45:06 +08002191 "xyz.openbmc_project.Settings",
2192 "/xyz/openbmc_project/Chassis/Control/NMISource",
2193 "org.freedesktop.DBus.Properties", "Set",
2194 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
Jason M. Bills418ce112021-09-08 15:15:05 -07002195 std::variant<std::string>{
2196 "xyz.openbmc_project.Chassis.Control.NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002197 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002198 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002199}
2200
Zev Weiss584aa132021-09-02 19:21:52 -05002201static void nmiButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002202{
Zev Weiss584aa132021-09-02 19:21:52 -05002203 nmiButtonIface->set_property("ButtonPressed", !state);
2204 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002205 {
2206 nmiButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002207 if (nmiButtonMasked)
2208 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002209 lg2::info("NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002210 }
2211 else
2212 {
2213 setNmiSource();
2214 }
2215 }
Zev Weiss584aa132021-09-02 19:21:52 -05002216}
2217
Zev Weiss584aa132021-09-02 19:21:52 -05002218static void idButtonHandler(bool state)
2219{
2220 idButtonIface->set_property("ButtonPressed", !state);
2221}
2222
Jason M. Billsfb957332021-01-28 13:18:46 -08002223static void pltRstHandler(bool pltRst)
2224{
2225 if (pltRst)
2226 {
2227 sendPowerControlEvent(Event::pltRstDeAssert);
2228 }
2229 else
2230 {
2231 sendPowerControlEvent(Event::pltRstAssert);
2232 }
2233}
2234
Patrick Williams439b9c32022-07-22 19:26:53 -05002235[[maybe_unused]] static void hostMiscHandler(sdbusplus::message_t& msg)
Jason M. Billsfb957332021-01-28 13:18:46 -08002236{
2237 std::string interfaceName;
2238 boost::container::flat_map<std::string, std::variant<bool>>
2239 propertiesChanged;
Jason M. Billsfb957332021-01-28 13:18:46 -08002240 try
2241 {
2242 msg.read(interfaceName, propertiesChanged);
2243 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002244 catch (const std::exception& e)
Jason M. Billsfb957332021-01-28 13:18:46 -08002245 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002246 lg2::error("Unable to read Host Misc status: {ERROR}", "ERROR", e);
Jason M. Billsfb957332021-01-28 13:18:46 -08002247 return;
2248 }
2249 if (propertiesChanged.empty())
2250 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002251 lg2::error("ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002252 return;
2253 }
2254
2255 for (auto& [property, value] : propertiesChanged)
2256 {
2257 if (property == "ESpiPlatformReset")
2258 {
2259 bool* pltRst = std::get_if<bool>(&value);
2260 if (pltRst == nullptr)
2261 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002262 lg2::error("{PROPERTY} property invalid", "PROPERTY", property);
Jason M. Billsfb957332021-01-28 13:18:46 -08002263 return;
2264 }
2265 pltRstHandler(*pltRst);
2266 }
2267 }
2268}
2269
Zev Weiss584aa132021-09-02 19:21:52 -05002270static void postCompleteHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002271{
Zev Weiss584aa132021-09-02 19:21:52 -05002272 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002273 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002274 sendPowerControlEvent(Event::postCompleteAssert);
Tim Lee86239182021-12-23 11:46:01 +08002275 setOperatingSystemState(OperatingSystemStateStage::Standby);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002276 }
2277 else
2278 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002279 sendPowerControlEvent(Event::postCompleteDeAssert);
Tim Lee86239182021-12-23 11:46:01 +08002280 setOperatingSystemState(OperatingSystemStateStage::Inactive);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002281 }
Zev Weiss584aa132021-09-02 19:21:52 -05002282}
2283
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302284static int loadConfigValues()
2285{
2286 const std::string configFilePath =
2287 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2288 ".json";
2289 std::ifstream configFile(configFilePath.c_str());
2290 if (!configFile.is_open())
2291 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002292 lg2::error("loadConfigValues: Cannot open config path \'{PATH}\'",
2293 "PATH", configFilePath);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302294 return -1;
2295 }
Zev Weiss1aa08b22021-09-15 17:06:20 -05002296 auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302297
Priyatharshan P70120512020-09-16 18:47:20 +05302298 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302299 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002300 lg2::error("Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302301 return -1;
2302 }
Priyatharshan P70120512020-09-16 18:47:20 +05302303 auto gpios = jsonData["gpio_configs"];
2304 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302305
Priyatharshan P70120512020-09-16 18:47:20 +05302306 ConfigData* tempGpioData;
2307
2308 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302309 {
Priyatharshan P70120512020-09-16 18:47:20 +05302310 if (!gpioConfig.contains("Name"))
2311 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002312 lg2::error("The 'Name' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302313 return -1;
2314 }
2315
2316 // Iterate through the powersignal map to check if the gpio json config
2317 // entry is valid
2318 std::string gpioName = gpioConfig["Name"];
2319 auto signalMapIter = powerSignalMap.find(gpioName);
2320 if (signalMapIter == powerSignalMap.end())
2321 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002322 lg2::error(
2323 "{GPIO_NAME} is not a recognized power-control signal name",
2324 "GPIO_NAME", gpioName);
Priyatharshan P70120512020-09-16 18:47:20 +05302325 return -1;
2326 }
2327
2328 // assign the power signal name to the corresponding structure reference
2329 // from map then fillup the structure with coressponding json config
2330 // value
2331 tempGpioData = signalMapIter->second;
2332 tempGpioData->name = gpioName;
2333
2334 if (!gpioConfig.contains("Type"))
2335 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002336 lg2::error("The \'Type\' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302337 return -1;
2338 }
2339
2340 std::string signalType = gpioConfig["Type"];
2341 if (signalType == "GPIO")
2342 {
2343 tempGpioData->type = ConfigType::GPIO;
2344 }
2345 else if (signalType == "DBUS")
2346 {
2347 tempGpioData->type = ConfigType::DBUS;
2348 }
2349 else
2350 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002351 lg2::error("{TYPE} is not a recognized power-control signal type",
2352 "TYPE", signalType);
Priyatharshan P70120512020-09-16 18:47:20 +05302353 return -1;
2354 }
2355
2356 if (tempGpioData->type == ConfigType::GPIO)
2357 {
2358 if (gpioConfig.contains("LineName"))
2359 {
2360 tempGpioData->lineName = gpioConfig["LineName"];
2361 }
2362 else
2363 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002364 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002365 "The \'LineName\' field must be defined for GPIO configuration");
Priyatharshan P70120512020-09-16 18:47:20 +05302366 return -1;
2367 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002368 if (gpioConfig.contains("Polarity"))
2369 {
2370 std::string polarity = gpioConfig["Polarity"];
2371 if (polarity == "ActiveLow")
2372 {
2373 tempGpioData->polarity = false;
2374 }
2375 else if (polarity == "ActiveHigh")
2376 {
2377 tempGpioData->polarity = true;
2378 }
2379 else
2380 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002381 lg2::error(
2382 "Polarity defined but not properly setup. Please only ActiveHigh or ActiveLow. Currently set to {POLARITY}",
2383 "POLARITY", polarity);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002384 return -1;
2385 }
2386 }
2387 else
2388 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002389 lg2::error("Polarity field not found for {GPIO_NAME}",
2390 "GPIO_NAME", tempGpioData->lineName);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002391 return -1;
2392 }
Priyatharshan P70120512020-09-16 18:47:20 +05302393 }
2394 else
2395 {
2396 // if dbus based gpio config is defined read and update the dbus
2397 // params corresponding to the gpio config instance
2398 for (auto& [key, dbusParamName] : dbusParams)
2399 {
Logananth Sundararaja4308042021-10-20 11:52:05 +05302400 if (!gpioConfig.contains(dbusParamName))
Priyatharshan P70120512020-09-16 18:47:20 +05302401 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002402 lg2::error(
2403 "The {DBUS_NAME} field must be defined for Dbus configuration ",
2404 "DBUS_NAME", dbusParamName);
Priyatharshan P70120512020-09-16 18:47:20 +05302405 return -1;
2406 }
2407 }
Logananth Sundararaja4308042021-10-20 11:52:05 +05302408 tempGpioData->dbusName =
2409 gpioConfig[dbusParams[DbusConfigType::name]];
2410 tempGpioData->path = gpioConfig[dbusParams[DbusConfigType::path]];
Priyatharshan P70120512020-09-16 18:47:20 +05302411 tempGpioData->interface =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302412 gpioConfig[dbusParams[DbusConfigType::interface]];
Priyatharshan P70120512020-09-16 18:47:20 +05302413 tempGpioData->lineName =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302414 gpioConfig[dbusParams[DbusConfigType::property]];
Priyatharshan P70120512020-09-16 18:47:20 +05302415 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302416 }
2417
Priyatharshan P70120512020-09-16 18:47:20 +05302418 // read and store the timer values from json config to Timer Map
2419 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302420 {
Priyatharshan P70120512020-09-16 18:47:20 +05302421 if (timers.contains(key.c_str()))
2422 {
2423 timerValue = timers[key.c_str()];
2424 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302425 }
2426
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302427 return 0;
2428}
Zev Weissa8f116a2021-09-01 21:08:30 -05002429
Patrick Williams439b9c32022-07-22 19:26:53 -05002430static bool getDbusMsgGPIOState(sdbusplus::message_t& msg,
Zev Weissa8f116a2021-09-01 21:08:30 -05002431 const std::string& lineName, bool& value)
2432{
2433 std::string thresholdInterface;
2434 std::string event;
2435 boost::container::flat_map<std::string, std::variant<bool>>
2436 propertiesChanged;
2437 try
2438 {
2439 msg.read(thresholdInterface, propertiesChanged);
2440 if (propertiesChanged.empty())
2441 {
2442 return false;
2443 }
2444
2445 event = propertiesChanged.begin()->first;
2446 if (event.empty() || event != lineName)
2447 {
2448 return false;
2449 }
2450
2451 value = std::get<bool>(propertiesChanged.begin()->second);
2452 return true;
2453 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002454 catch (const std::exception& e)
Zev Weissa8f116a2021-09-01 21:08:30 -05002455 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002456 lg2::error(
2457 "exception while reading dbus property \'{DBUS_NAME}\': {ERROR}",
2458 "DBUS_NAME", lineName, "ERROR", e);
Zev Weissa8f116a2021-09-01 21:08:30 -05002459 return false;
2460 }
2461}
2462
Patrick Williams439b9c32022-07-22 19:26:53 -05002463static sdbusplus::bus::match_t
Zev Weissa8f116a2021-09-01 21:08:30 -05002464 dbusGPIOMatcher(const ConfigData& cfg, std::function<void(bool)> onMatch)
2465{
Patrick Williams439b9c32022-07-22 19:26:53 -05002466 auto pulseEventMatcherCallback = [&cfg,
2467 onMatch](sdbusplus::message_t& msg) {
2468 bool value = false;
2469 if (!getDbusMsgGPIOState(msg, cfg.lineName, value))
2470 {
2471 return;
2472 }
2473 onMatch(value);
2474 };
Zev Weissa8f116a2021-09-01 21:08:30 -05002475
Patrick Williams439b9c32022-07-22 19:26:53 -05002476 return sdbusplus::bus::match_t(
2477 static_cast<sdbusplus::bus_t&>(*conn),
Zev Weissa8f116a2021-09-01 21:08:30 -05002478 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2479 "PropertiesChanged',arg0='" +
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302480 cfg.interface + "'",
Zev Weissa8f116a2021-09-01 21:08:30 -05002481 std::move(pulseEventMatcherCallback));
2482}
2483
Priyatharshan P70120512020-09-16 18:47:20 +05302484int getProperty(ConfigData& configData)
2485{
2486 auto method = conn->new_method_call(
2487 configData.dbusName.c_str(), configData.path.c_str(),
2488 "org.freedesktop.DBus.Properties", "Get");
2489 method.append(configData.interface.c_str(), configData.lineName.c_str());
2490
2491 auto reply = conn->call(method);
2492 if (reply.is_method_error())
2493 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002494 lg2::error(
2495 "Error reading {PROPERTY} D-Bus property on interface {INTERFACE} and path {PATH}",
2496 "PROPERTY", configData.lineName, "INTERFACE", configData.interface,
2497 "PATH", configData.path);
Priyatharshan P70120512020-09-16 18:47:20 +05302498 return -1;
2499 }
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302500 std::variant<bool> resp;
Priyatharshan P70120512020-09-16 18:47:20 +05302501 reply.read(resp);
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302502 auto respValue = std::get_if<bool>(&resp);
Priyatharshan P70120512020-09-16 18:47:20 +05302503 if (!respValue)
2504 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002505 lg2::error("Error: {PROPERTY} D-Bus property is not the expected type",
2506 "PROPERTY", configData.lineName);
Priyatharshan P70120512020-09-16 18:47:20 +05302507 return -1;
2508 }
2509 return (*respValue);
2510}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002511} // namespace power_control
2512
2513int main(int argc, char* argv[])
2514{
Lei YU92caa4c2021-02-23 16:59:25 +08002515 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05302516
2517 if (argc > 1)
2518 {
2519 node = argv[1];
2520 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002521 lg2::info("Start Chassis power control service for host : {NODE}", "NODE",
2522 node);
Priyatharshan P70120512020-09-16 18:47:20 +05302523
Lei YU92caa4c2021-02-23 16:59:25 +08002524 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002525
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302526 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08002527 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302528 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002529 lg2::error("Host{NODE}: Error in Parsing...", "NODE", node);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302530 }
Naveen Mosesec972d82021-07-16 21:19:23 +05302531 /* Currently for single host based systems additional busname is added
2532 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
2533 Going forward for single hosts the old bus name without zero numbering
2534 will be removed when all other applications adapted to the
2535 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
2536
2537 if (node == "0")
2538 {
2539 // Request all the dbus names
2540 conn->request_name(hostDbusName.c_str());
2541 conn->request_name(chassisDbusName.c_str());
2542 conn->request_name(osDbusName.c_str());
2543 conn->request_name(buttonDbusName.c_str());
2544 conn->request_name(nmiDbusName.c_str());
2545 conn->request_name(rstCauseDbusName.c_str());
2546 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302547
Zev Weissc4005bd2021-09-01 22:30:23 -05002548 hostDbusName += node;
2549 chassisDbusName += node;
2550 osDbusName += node;
2551 buttonDbusName += node;
2552 nmiDbusName += node;
2553 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002554
Priyatharshan P70120512020-09-16 18:47:20 +05302555 // Request all the dbus names
2556 conn->request_name(hostDbusName.c_str());
2557 conn->request_name(chassisDbusName.c_str());
2558 conn->request_name(osDbusName.c_str());
2559 conn->request_name(buttonDbusName.c_str());
2560 conn->request_name(nmiDbusName.c_str());
2561 conn->request_name(rstCauseDbusName.c_str());
2562
2563 if (sioPwrGoodConfig.lineName.empty() ||
2564 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05302565 {
Lei YU92caa4c2021-02-23 16:59:25 +08002566 sioEnabled = false;
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002567 lg2::info("SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05302568 }
2569
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002570 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302571 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002572 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002573 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302574 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302575 {
2576 return -1;
2577 }
2578 }
Priyatharshan P70120512020-09-16 18:47:20 +05302579 else if (powerOkConfig.type == ConfigType::DBUS)
2580 {
2581
Patrick Williams439b9c32022-07-22 19:26:53 -05002582 static sdbusplus::bus::match_t powerOkEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002583 power_control::dbusGPIOMatcher(powerOkConfig, psPowerOKHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302584 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302585 else
2586 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002587 lg2::error("PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002588 return -1;
2589 }
2590
Lei YU92caa4c2021-02-23 16:59:25 +08002591 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002592 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05302593 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302594 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302595 {
Priyatharshan P70120512020-09-16 18:47:20 +05302596 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002597 sioPowerGoodHandler, sioPowerGoodLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302598 sioPowerGoodEvent))
2599 {
2600 return -1;
2601 }
2602 }
2603 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
2604 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002605 static sdbusplus::bus::match_t sioPwrGoodEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002606 power_control::dbusGPIOMatcher(sioPwrGoodConfig,
2607 sioPowerGoodHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302608 }
2609 else
2610 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002611 lg2::error(
Priyatharshan P70120512020-09-16 18:47:20 +05302612 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302613 return -1;
2614 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002615
Priyatharshan P19c47a32020-08-12 18:16:43 +05302616 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302617 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302618 {
Priyatharshan P70120512020-09-16 18:47:20 +05302619 if (!requestGPIOEvents(sioOnControlConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002620 sioOnControlHandler, sioOnControlLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302621 sioOnControlEvent))
2622 {
2623 return -1;
2624 }
2625 }
2626 else if (sioOnControlConfig.type == ConfigType::DBUS)
2627 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002628 static sdbusplus::bus::match_t sioOnControlEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002629 power_control::dbusGPIOMatcher(sioOnControlConfig,
2630 sioOnControlHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302631 }
2632 else
2633 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002634 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002635 "sioOnControl name should be configured from jsonconfig file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302636 return -1;
2637 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002638
Priyatharshan P19c47a32020-08-12 18:16:43 +05302639 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302640 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302641 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002642 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
Priyatharshan P70120512020-09-16 18:47:20 +05302643 sioS5Line, sioS5Event))
2644 {
2645 return -1;
2646 }
2647 }
2648 else if (sioS5Config.type == ConfigType::DBUS)
2649 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002650 static sdbusplus::bus::match_t sioS5EventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002651 power_control::dbusGPIOMatcher(sioS5Config, sioS5Handler);
Priyatharshan P70120512020-09-16 18:47:20 +05302652 }
2653 else
2654 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002655 lg2::error("sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302656 return -1;
2657 }
2658 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002659
2660 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302661 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002662 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002663 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
2664 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302665 {
2666 return -1;
2667 }
2668 }
Priyatharshan P70120512020-09-16 18:47:20 +05302669 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302670 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002671 static sdbusplus::bus::match_t powerButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002672 power_control::dbusGPIOMatcher(powerButtonConfig,
2673 powerButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002674 }
2675
2676 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302677 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002678 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002679 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
2680 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302681 {
2682 return -1;
2683 }
2684 }
Priyatharshan P70120512020-09-16 18:47:20 +05302685 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302686 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002687 static sdbusplus::bus::match_t resetButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002688 power_control::dbusGPIOMatcher(resetButtonConfig,
2689 resetButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002690 }
2691
2692 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302693 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302694 {
Priyatharshan P70120512020-09-16 18:47:20 +05302695 if (!nmiButtonConfig.lineName.empty())
2696 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002697 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302698 nmiButtonLine, nmiButtonEvent);
2699 }
2700 }
2701 else if (nmiButtonConfig.type == ConfigType::DBUS)
2702 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002703 static sdbusplus::bus::match_t nmiButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002704 power_control::dbusGPIOMatcher(nmiButtonConfig, nmiButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302705 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002706
2707 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302708 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302709 {
Priyatharshan P70120512020-09-16 18:47:20 +05302710 if (!idButtonConfig.lineName.empty())
2711 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002712 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302713 idButtonLine, idButtonEvent);
2714 }
2715 }
2716 else if (idButtonConfig.type == ConfigType::DBUS)
2717 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002718 static sdbusplus::bus::match_t idButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002719 power_control::dbusGPIOMatcher(idButtonConfig, idButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302720 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002721
Jason M. Billsfb957332021-01-28 13:18:46 -08002722#ifdef USE_PLT_RST
Patrick Williams439b9c32022-07-22 19:26:53 -05002723 sdbusplus::bus::match_t pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08002724 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08002725 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2726 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08002727 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08002728#endif
2729
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002730 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302731 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002732 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002733 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
2734 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302735 {
2736 return -1;
2737 }
2738 }
Priyatharshan P70120512020-09-16 18:47:20 +05302739 else if (postCompleteConfig.type == ConfigType::DBUS)
2740 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002741 static sdbusplus::bus::match_t postCompleteEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002742 power_control::dbusGPIOMatcher(postCompleteConfig,
2743 postCompleteHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302744 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302745 else
2746 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002747 lg2::error(
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002748 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002749 return -1;
2750 }
2751
2752 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05302753 if (!nmiOutConfig.lineName.empty())
2754 {
Jian Zhang461a1662022-09-22 11:29:01 +08002755 setGPIOOutput(nmiOutConfig.lineName, !nmiOutConfig.polarity,
2756 nmiOutLine);
Priyatharshan P70120512020-09-16 18:47:20 +05302757 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002758
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002759 // Initialize POWER_OUT and RESET_OUT GPIO.
2760 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05302761 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002762 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002763 if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
2764 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302765 {
2766 return -1;
2767 }
2768 }
2769 else
2770 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002771 lg2::error("powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002772 return -1;
2773 }
2774
Priyatharshan P70120512020-09-16 18:47:20 +05302775 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002776 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002777 if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
2778 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302779 {
2780 return -1;
2781 }
2782 }
2783 else
2784 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002785 lg2::error("ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002786 return -1;
2787 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002788 // Release line
2789 line.reset();
2790
Matt Simmering58e379d2022-09-23 14:45:50 -07002791 // Initialize the power state and operating system state
Lei YU92caa4c2021-02-23 16:59:25 +08002792 powerState = PowerState::off;
Matt Simmering58e379d2022-09-23 14:45:50 -07002793 operatingSystemState = OperatingSystemStateStage::Inactive;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002794 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05302795
2796 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002797 {
Jean-Marie Verdun61b4a5b2021-09-19 08:53:28 -04002798 if (psPowerOKLine.get_value() > 0 ||
Lei YUa37c2472021-09-26 15:57:12 +08002799 (sioEnabled &&
2800 (sioPowerGoodLine.get_value() == sioPwrGoodConfig.polarity)))
Priyatharshan P70120512020-09-16 18:47:20 +05302801 {
2802 powerState = PowerState::on;
2803 }
2804 }
2805 else
2806 {
2807 if (getProperty(powerOkConfig))
2808 {
2809 powerState = PowerState::on;
2810 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002811 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002812 // Check if we need to start the Power Restore policy
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03002813 if (powerState != PowerState::on)
2814 {
2815 powerRestore.run();
2816 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002817
Lei YU92caa4c2021-02-23 16:59:25 +08002818 if (nmiOutLine)
2819 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002820
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002821 lg2::info("Initializing power state.");
Lei YU92caa4c2021-02-23 16:59:25 +08002822 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002823
2824 // Power Control Service
2825 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002826 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002827
2828 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05302829 hostIface =
2830 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
2831 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002832 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08002833 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002834 "RequestedHostTransition",
2835 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2836 [](const std::string& requested, std::string& resp) {
2837 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2838 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002839 // if power button is masked, ignore this
2840 if (!powerButtonMask)
2841 {
2842 sendPowerControlEvent(Event::gracefulPowerOffRequest);
2843 addRestartCause(RestartCause::command);
2844 }
2845 else
2846 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002847 lg2::info("Power Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002848 throw std::invalid_argument("Transition Request Masked");
2849 return 0;
2850 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002851 }
2852 else if (requested ==
2853 "xyz.openbmc_project.State.Host.Transition.On")
2854 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002855 // if power button is masked, ignore this
2856 if (!powerButtonMask)
2857 {
2858 sendPowerControlEvent(Event::powerOnRequest);
2859 addRestartCause(RestartCause::command);
2860 }
2861 else
2862 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002863 lg2::info("Power Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002864 throw std::invalid_argument("Transition Request Masked");
2865 return 0;
2866 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002867 }
2868 else if (requested ==
2869 "xyz.openbmc_project.State.Host.Transition.Reboot")
2870 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002871 // if power button is masked, ignore this
2872 if (!powerButtonMask)
2873 {
2874 sendPowerControlEvent(Event::powerCycleRequest);
2875 addRestartCause(RestartCause::command);
2876 }
2877 else
2878 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002879 lg2::info("Power Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002880 throw std::invalid_argument("Transition Request Masked");
2881 return 0;
2882 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002883 }
Jason M. Bills418ce112021-09-08 15:15:05 -07002884 else if (
2885 requested ==
2886 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot")
Jason M. Billse7520ba2020-01-31 11:19:03 -08002887 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002888 // if reset button is masked, ignore this
2889 if (!resetButtonMask)
2890 {
2891 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
2892 addRestartCause(RestartCause::command);
2893 }
2894 else
2895 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002896 lg2::info("Reset Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002897 throw std::invalid_argument("Transition Request Masked");
2898 return 0;
2899 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002900 }
Jason M. Bills418ce112021-09-08 15:15:05 -07002901 else if (
2902 requested ==
2903 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot")
Jason M. Billse7520ba2020-01-31 11:19:03 -08002904 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002905 // if reset button is masked, ignore this
2906 if (!resetButtonMask)
2907 {
2908 sendPowerControlEvent(Event::resetRequest);
2909 addRestartCause(RestartCause::command);
2910 }
2911 else
2912 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002913 lg2::info("Reset Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002914 throw std::invalid_argument("Transition Request Masked");
2915 return 0;
2916 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002917 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002918 else
2919 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002920 lg2::error("Unrecognized host state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002921 throw std::invalid_argument("Unrecognized Transition Request");
2922 return 0;
2923 }
2924 resp = requested;
2925 return 1;
2926 });
Lei YU92caa4c2021-02-23 16:59:25 +08002927 hostIface->register_property("CurrentHostState",
2928 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002929
Lei YU92caa4c2021-02-23 16:59:25 +08002930 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002931
2932 // Chassis Control Service
2933 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002934 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002935
2936 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002937 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05302938 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002939 "xyz.openbmc_project.State.Chassis");
2940
Lei YU92caa4c2021-02-23 16:59:25 +08002941 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002942 "RequestedPowerTransition",
2943 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
2944 [](const std::string& requested, std::string& resp) {
2945 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
2946 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002947 // if power button is masked, ignore this
2948 if (!powerButtonMask)
2949 {
2950 sendPowerControlEvent(Event::powerOffRequest);
2951 addRestartCause(RestartCause::command);
2952 }
2953 else
2954 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002955 lg2::info("Power Button Masked.");
Vernon Mauery2a269432021-07-14 10:00:21 -07002956 throw std::invalid_argument("Transition Request Masked");
2957 return 0;
2958 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002959 }
2960 else if (requested ==
2961 "xyz.openbmc_project.State.Chassis.Transition.On")
2962 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002963 // if power button is masked, ignore this
2964 if (!powerButtonMask)
2965 {
2966 sendPowerControlEvent(Event::powerOnRequest);
2967 addRestartCause(RestartCause::command);
2968 }
2969 else
2970 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002971 lg2::info("Power Button Masked.");
Vernon Mauery2a269432021-07-14 10:00:21 -07002972 throw std::invalid_argument("Transition Request Masked");
2973 return 0;
2974 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002975 }
2976 else if (requested ==
2977 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2978 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002979 // if power button is masked, ignore this
2980 if (!powerButtonMask)
2981 {
2982 sendPowerControlEvent(Event::powerCycleRequest);
2983 addRestartCause(RestartCause::command);
2984 }
2985 else
2986 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002987 lg2::info("Power Button Masked.");
Vernon Mauery2a269432021-07-14 10:00:21 -07002988 throw std::invalid_argument("Transition Request Masked");
2989 return 0;
2990 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002991 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002992 else
2993 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002994 lg2::error("Unrecognized chassis state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002995 throw std::invalid_argument("Unrecognized Transition Request");
2996 return 0;
2997 }
2998 resp = requested;
2999 return 1;
3000 });
Lei YU92caa4c2021-02-23 16:59:25 +08003001 chassisIface->register_property("CurrentPowerState",
3002 std::string(getChassisState(powerState)));
3003 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003004
Lei YU92caa4c2021-02-23 16:59:25 +08003005 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003006
Vijay Khemka04175c22020-10-09 14:28:11 -07003007#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003008 // Chassis System Service
3009 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003010 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003011
3012 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003013 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003014 "/xyz/openbmc_project/state/chassis_system0",
3015 "xyz.openbmc_project.State.Chassis");
3016
Lei YU92caa4c2021-02-23 16:59:25 +08003017 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003018 "RequestedPowerTransition",
3019 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3020 [](const std::string& requested, std::string& resp) {
3021 if (requested ==
3022 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3023 {
Lei YU92caa4c2021-02-23 16:59:25 +08003024 systemReset();
3025 addRestartCause(RestartCause::command);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003026 }
3027 else
3028 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003029 lg2::error(
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003030 "Unrecognized chassis system state transition request.");
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003031 throw std::invalid_argument("Unrecognized Transition Request");
3032 return 0;
3033 }
3034 resp = requested;
3035 return 1;
3036 });
Lei YU92caa4c2021-02-23 16:59:25 +08003037 chassisSysIface->register_property(
3038 "CurrentPowerState", std::string(getChassisState(powerState)));
3039 chassisSysIface->register_property("LastStateChangeTime",
3040 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003041
Lei YU92caa4c2021-02-23 16:59:25 +08003042 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003043
Naveen Moses117c34e2021-05-26 20:10:51 +05303044 if (!slotPowerConfig.lineName.empty())
3045 {
3046 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3047 {
3048 return -1;
3049 }
3050
3051 slotPowerState = SlotPowerState::off;
3052 if (slotPowerLine.get_value() > 0)
3053 {
3054 slotPowerState = SlotPowerState::on;
3055 }
3056
3057 chassisSlotIface = chassisSysServer.add_interface(
3058 "/xyz/openbmc_project/state/chassis_system" + node,
3059 "xyz.openbmc_project.State.Chassis");
3060 chassisSlotIface->register_property(
3061 "RequestedPowerTransition",
3062 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3063 [](const std::string& requested, std::string& resp) {
3064 if (requested ==
3065 "xyz.openbmc_project.State.Chassis.Transition.On")
3066 {
3067 slotPowerOn();
3068 }
3069 else if (requested ==
3070 "xyz.openbmc_project.State.Chassis.Transition.Off")
3071 {
3072 slotPowerOff();
3073 }
Jason M. Bills418ce112021-09-08 15:15:05 -07003074 else if (
3075 requested ==
3076 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
Naveen Moses117c34e2021-05-26 20:10:51 +05303077 {
3078 slotPowerCycle();
3079 }
3080 else
3081 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003082 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07003083 "Unrecognized chassis system state transition request.\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05303084 throw std::invalid_argument(
3085 "Unrecognized Transition Request");
3086 return 0;
3087 }
3088 resp = requested;
3089 return 1;
3090 });
3091 chassisSlotIface->register_property(
3092 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3093 chassisSlotIface->register_property("LastStateChangeTime",
3094 getCurrentTimeMs());
3095 chassisSlotIface->initialize();
3096 }
3097#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003098 // Buttons Service
3099 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003100 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003101
Priyatharshan P70120512020-09-16 18:47:20 +05303102 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003103 {
Priyatharshan P70120512020-09-16 18:47:20 +05303104 // Power Button Interface
3105 power_control::powerButtonIface = buttonsServer.add_interface(
3106 "/xyz/openbmc_project/chassis/buttons/power",
3107 "xyz.openbmc_project.Chassis.Buttons");
3108
3109 powerButtonIface->register_property(
3110 "ButtonMasked", false, [](const bool requested, bool& current) {
3111 if (requested)
3112 {
3113 if (powerButtonMask)
3114 {
3115 return 1;
3116 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003117 if (!setGPIOOutput(powerOutConfig.lineName,
3118 !powerOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303119 powerButtonMask))
3120 {
3121 throw std::runtime_error("Failed to request GPIO");
3122 return 0;
3123 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003124 lg2::info("Power Button Masked.");
Priyatharshan P70120512020-09-16 18:47:20 +05303125 }
3126 else
3127 {
3128 if (!powerButtonMask)
3129 {
3130 return 1;
3131 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003132 lg2::info("Power Button Un-masked");
Priyatharshan P70120512020-09-16 18:47:20 +05303133 powerButtonMask.reset();
3134 }
3135 // Update the mask setting
3136 current = requested;
3137 return 1;
3138 });
3139
3140 // Check power button state
3141 bool powerButtonPressed;
3142 if (powerButtonConfig.type == ConfigType::GPIO)
3143 {
3144 powerButtonPressed = powerButtonLine.get_value() == 0;
3145 }
3146 else
3147 {
3148 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3149 }
3150
3151 powerButtonIface->register_property("ButtonPressed",
3152 powerButtonPressed);
3153
3154 powerButtonIface->initialize();
3155 }
3156
3157 if (!resetButtonConfig.lineName.empty())
3158 {
3159 // Reset Button Interface
3160
Lei YU92caa4c2021-02-23 16:59:25 +08003161 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003162 "/xyz/openbmc_project/chassis/buttons/reset",
3163 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003164
Lei YU92caa4c2021-02-23 16:59:25 +08003165 resetButtonIface->register_property(
John Wang6c090072020-09-30 13:32:16 +08003166 "ButtonMasked", false, [](const bool requested, bool& current) {
3167 if (requested)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003168 {
Lei YU92caa4c2021-02-23 16:59:25 +08003169 if (resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003170 {
3171 return 1;
3172 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003173 if (!setGPIOOutput(resetOutConfig.lineName,
3174 !resetOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303175 resetButtonMask))
John Wang6c090072020-09-30 13:32:16 +08003176 {
3177 throw std::runtime_error("Failed to request GPIO");
3178 return 0;
3179 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003180 lg2::info("Reset Button Masked.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003181 }
John Wang6c090072020-09-30 13:32:16 +08003182 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003183 {
Lei YU92caa4c2021-02-23 16:59:25 +08003184 if (!resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003185 {
3186 return 1;
3187 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003188 lg2::info("Reset Button Un-masked");
Lei YU92caa4c2021-02-23 16:59:25 +08003189 resetButtonMask.reset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003190 }
John Wang6c090072020-09-30 13:32:16 +08003191 // Update the mask setting
3192 current = requested;
3193 return 1;
3194 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003195
John Wang6c090072020-09-30 13:32:16 +08003196 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303197 bool resetButtonPressed;
3198 if (resetButtonConfig.type == ConfigType::GPIO)
3199 {
3200 resetButtonPressed = resetButtonLine.get_value() == 0;
3201 }
3202 else
3203 {
3204 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3205 }
3206
Lei YU92caa4c2021-02-23 16:59:25 +08003207 resetButtonIface->register_property("ButtonPressed",
3208 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003209
Lei YU92caa4c2021-02-23 16:59:25 +08003210 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003211 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003212
Lei YU92caa4c2021-02-23 16:59:25 +08003213 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003214 {
3215 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003216 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003217 "/xyz/openbmc_project/chassis/buttons/nmi",
3218 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003219
Lei YU92caa4c2021-02-23 16:59:25 +08003220 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003221 "ButtonMasked", false, [](const bool requested, bool& current) {
Lei YU92caa4c2021-02-23 16:59:25 +08003222 if (nmiButtonMasked == requested)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003223 {
3224 // NMI button mask is already set as requested, so no change
3225 return 1;
3226 }
3227 if (requested)
3228 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003229 lg2::info("NMI Button Masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003230 nmiButtonMasked = true;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003231 }
3232 else
3233 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003234 lg2::info("NMI Button Un-masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003235 nmiButtonMasked = false;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003236 }
3237 // Update the mask setting
Lei YU92caa4c2021-02-23 16:59:25 +08003238 current = nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003239 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003240 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003241
Vijay Khemka33a532d2019-11-14 16:50:35 -08003242 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303243 bool nmiButtonPressed;
3244 if (nmiButtonConfig.type == ConfigType::GPIO)
3245 {
3246 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3247 }
3248 else
3249 {
3250 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3251 }
3252
Lei YU92caa4c2021-02-23 16:59:25 +08003253 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003254
Lei YU92caa4c2021-02-23 16:59:25 +08003255 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003256 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003257
Lei YU92caa4c2021-02-23 16:59:25 +08003258 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003259 {
3260 // NMI out Service
3261 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003262 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003263
Vijay Khemka33a532d2019-11-14 16:50:35 -08003264 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303265 nmiOutIface = nmiOutServer.add_interface(
3266 "/xyz/openbmc_project/control/host" + node + "/nmi",
3267 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003268 nmiOutIface->register_method("NMI", nmiReset);
3269 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003270 }
Chen Yugang174ec662019-08-19 19:58:49 +08003271
Lei YU92caa4c2021-02-23 16:59:25 +08003272 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003273 {
3274 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003275 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003276 "/xyz/openbmc_project/chassis/buttons/id",
3277 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003278
Vijay Khemka33a532d2019-11-14 16:50:35 -08003279 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303280 bool idButtonPressed;
3281 if (idButtonConfig.type == ConfigType::GPIO)
3282 {
3283 idButtonPressed = idButtonLine.get_value() == 0;
3284 }
3285 else
3286 {
3287 idButtonPressed = getProperty(idButtonConfig) == 0;
3288 }
3289
Lei YU92caa4c2021-02-23 16:59:25 +08003290 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003291
Lei YU92caa4c2021-02-23 16:59:25 +08003292 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003293 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003294
3295 // OS State Service
3296 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003297 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003298
3299 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003300 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003301 "/xyz/openbmc_project/state/os",
3302 "xyz.openbmc_project.State.OperatingSystem.Status");
3303
3304 // Get the initial OS state based on POST complete
3305 // 0: Asserted, OS state is "Standby" (ready to boot)
3306 // 1: De-Asserted, OS state is "Inactive"
Tim Lee86239182021-12-23 11:46:01 +08003307 OperatingSystemStateStage osState;
Priyatharshan P70120512020-09-16 18:47:20 +05303308 if (postCompleteConfig.type == ConfigType::GPIO)
3309 {
Tim Lee86239182021-12-23 11:46:01 +08003310 osState = postCompleteLine.get_value() > 0
3311 ? OperatingSystemStateStage::Inactive
3312 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303313 }
3314 else
3315 {
Tim Lee86239182021-12-23 11:46:01 +08003316 osState = getProperty(postCompleteConfig) > 0
3317 ? OperatingSystemStateStage::Inactive
3318 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303319 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003320
Tim Lee86239182021-12-23 11:46:01 +08003321 osIface->register_property(
3322 "OperatingSystemState",
3323 std::string(getOperatingSystemStateStage(osState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003324
Lei YU92caa4c2021-02-23 16:59:25 +08003325 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003326
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003327 // Restart Cause Service
3328 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003329 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003330
3331 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003332 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303333 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003334 "xyz.openbmc_project.Control.Host.RestartCause");
3335
Lei YU92caa4c2021-02-23 16:59:25 +08003336 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003337 "RestartCause",
3338 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3339
Lei YU92caa4c2021-02-23 16:59:25 +08003340 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003341 "RequestedRestartCause",
3342 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3343 [](const std::string& requested, std::string& resp) {
3344 if (requested ==
3345 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3346 {
Lei YU92caa4c2021-02-23 16:59:25 +08003347 addRestartCause(RestartCause::watchdog);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003348 }
3349 else
3350 {
3351 throw std::invalid_argument(
3352 "Unrecognized RestartCause Request");
3353 return 0;
3354 }
3355
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003356 lg2::info("RestartCause requested: {RESTART_CAUSE}",
3357 "RESTART_CAUSE", requested);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003358 resp = requested;
3359 return 1;
3360 });
3361
Lei YU92caa4c2021-02-23 16:59:25 +08003362 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003363
Lei YU92caa4c2021-02-23 16:59:25 +08003364 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003365
Lei YU92caa4c2021-02-23 16:59:25 +08003366 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003367
3368 return 0;
3369}