blob: 563b008764f1cbd1c654626ded1f44a07263984d [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;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700130
Priyatharshan P70120512020-09-16 18:47:20 +0530131// This map contains all timer values that are to be read from json config
132boost::container::flat_map<std::string, int> TimerMap = {
Jason M. Billsaeefe042021-09-08 14:56:11 -0700133 {"PowerPulseMs", 200},
134 {"ForceOffPulseMs", 15000},
135 {"ResetPulseMs", 500},
136 {"PowerCycleMs", 5000},
137 {"SioPowerGoodWatchdogMs", 1000},
138 {"PsPowerOKWatchdogMs", 8000},
139 {"GracefulPowerOffS", (5 * 60)},
140 {"WarmResetCheckMs", 500},
141 {"PowerOffSaveMs", 7000},
142 {"SlotPowerCycleMs", 200}};
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700143
144static bool nmiEnabled = true;
Priyatharshan P19c47a32020-08-12 18:16:43 +0530145static bool sioEnabled = true;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700146
147// Timers
148// Time holding GPIOs asserted
149static boost::asio::steady_timer gpioAssertTimer(io);
150// Time between off and on during a power cycle
151static boost::asio::steady_timer powerCycleTimer(io);
152// Time OS gracefully powering off
153static boost::asio::steady_timer gracefulPowerOffTimer(io);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700154// Time the warm reset check
155static boost::asio::steady_timer warmResetCheckTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700156// Time power supply power OK assertion on power-on
157static boost::asio::steady_timer psPowerOKWatchdogTimer(io);
158// Time SIO power good assertion on power-on
159static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io);
160// Time power-off state save for power loss tracking
161static boost::asio::steady_timer powerStateSaveTimer(io);
162// POH timer
163static boost::asio::steady_timer pohCounterTimer(io);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700164// Time when to allow restart cause updates
165static boost::asio::steady_timer restartCauseTimer(io);
Naveen Moses117c34e2021-05-26 20:10:51 +0530166static boost::asio::steady_timer slotPowerCycleTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700167
168// GPIO Lines and Event Descriptors
169static gpiod::line psPowerOKLine;
170static boost::asio::posix::stream_descriptor psPowerOKEvent(io);
171static gpiod::line sioPowerGoodLine;
172static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io);
173static gpiod::line sioOnControlLine;
174static boost::asio::posix::stream_descriptor sioOnControlEvent(io);
175static gpiod::line sioS5Line;
176static boost::asio::posix::stream_descriptor sioS5Event(io);
177static gpiod::line powerButtonLine;
178static boost::asio::posix::stream_descriptor powerButtonEvent(io);
179static gpiod::line resetButtonLine;
180static boost::asio::posix::stream_descriptor resetButtonEvent(io);
181static gpiod::line nmiButtonLine;
182static boost::asio::posix::stream_descriptor nmiButtonEvent(io);
183static gpiod::line idButtonLine;
184static boost::asio::posix::stream_descriptor idButtonEvent(io);
185static gpiod::line postCompleteLine;
186static boost::asio::posix::stream_descriptor postCompleteEvent(io);
187static gpiod::line nmiOutLine;
Naveen Moses117c34e2021-05-26 20:10:51 +0530188static gpiod::line slotPowerLine;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700189
190static constexpr uint8_t beepPowerFail = 8;
191
192static void beep(const uint8_t& beepPriority)
193{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800194 lg2::info("Beep with priority: {BEEP_PRIORITY}", "BEEP_PRIORITY",
195 beepPriority);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700196
197 conn->async_method_call(
198 [](boost::system::error_code ec) {
199 if (ec)
200 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800201 lg2::error(
202 "beep returned error with async_method_call (ec = {ERROR_MSG})",
203 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700204 return;
205 }
206 },
207 "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
208 "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
209}
210
Tim Lee86239182021-12-23 11:46:01 +0800211enum class OperatingSystemStateStage
212{
213 Inactive,
214 Standby,
215};
216static constexpr std::string_view
217 getOperatingSystemStateStage(const OperatingSystemStateStage stage)
218{
219 switch (stage)
220 {
221 case OperatingSystemStateStage::Inactive:
222 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
223 break;
224 case OperatingSystemStateStage::Standby:
225 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Standby";
226 break;
227 default:
228 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
229 break;
230 }
231};
232static void setOperatingSystemState(const OperatingSystemStateStage stage)
233{
234 osIface->set_property("OperatingSystemState",
235 std::string(getOperatingSystemStateStage(stage)));
236
237 lg2::info("Moving os state to {STATE} stage", "STATE",
238 getOperatingSystemStateStage(stage));
239}
240
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700241enum class PowerState
242{
243 on,
244 waitForPSPowerOK,
245 waitForSIOPowerGood,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700246 off,
247 transitionToOff,
248 gracefulTransitionToOff,
249 cycleOff,
250 transitionToCycleOff,
251 gracefulTransitionToCycleOff,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700252 checkForWarmReset,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700253};
254static PowerState powerState;
255static std::string getPowerStateName(PowerState state)
256{
257 switch (state)
258 {
259 case PowerState::on:
260 return "On";
261 break;
262 case PowerState::waitForPSPowerOK:
263 return "Wait for Power Supply Power OK";
264 break;
265 case PowerState::waitForSIOPowerGood:
266 return "Wait for SIO Power Good";
267 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700268 case PowerState::off:
269 return "Off";
270 break;
271 case PowerState::transitionToOff:
272 return "Transition to Off";
273 break;
274 case PowerState::gracefulTransitionToOff:
275 return "Graceful Transition to Off";
276 break;
277 case PowerState::cycleOff:
278 return "Power Cycle Off";
279 break;
280 case PowerState::transitionToCycleOff:
281 return "Transition to Power Cycle Off";
282 break;
283 case PowerState::gracefulTransitionToCycleOff:
284 return "Graceful Transition to Power Cycle Off";
285 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700286 case PowerState::checkForWarmReset:
287 return "Check for Warm Reset";
288 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700289 default:
290 return "unknown state: " + std::to_string(static_cast<int>(state));
291 break;
292 }
293}
294static void logStateTransition(const PowerState state)
295{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800296 lg2::info("Host{HOST}: Moving to \"{STATE}\" state", "HOST", node, "STATE",
297 getPowerStateName(state));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700298}
299
300enum class Event
301{
302 psPowerOKAssert,
303 psPowerOKDeAssert,
304 sioPowerGoodAssert,
305 sioPowerGoodDeAssert,
306 sioS5Assert,
307 sioS5DeAssert,
Jason M. Billsfb957332021-01-28 13:18:46 -0800308 pltRstAssert,
309 pltRstDeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700310 postCompleteAssert,
311 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700312 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700313 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700314 powerCycleTimerExpired,
315 psPowerOKWatchdogTimerExpired,
316 sioPowerGoodWatchdogTimerExpired,
317 gracefulPowerOffTimerExpired,
318 powerOnRequest,
319 powerOffRequest,
320 powerCycleRequest,
321 resetRequest,
322 gracefulPowerOffRequest,
323 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700324 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700325};
326static std::string getEventName(Event event)
327{
328 switch (event)
329 {
330 case Event::psPowerOKAssert:
331 return "power supply power OK assert";
332 break;
333 case Event::psPowerOKDeAssert:
334 return "power supply power OK de-assert";
335 break;
336 case Event::sioPowerGoodAssert:
337 return "SIO power good assert";
338 break;
339 case Event::sioPowerGoodDeAssert:
340 return "SIO power good de-assert";
341 break;
342 case Event::sioS5Assert:
343 return "SIO S5 assert";
344 break;
345 case Event::sioS5DeAssert:
346 return "SIO S5 de-assert";
347 break;
Jason M. Billsfb957332021-01-28 13:18:46 -0800348 case Event::pltRstAssert:
349 return "PLT_RST assert";
350 break;
351 case Event::pltRstDeAssert:
352 return "PLT_RST de-assert";
353 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700354 case Event::postCompleteAssert:
355 return "POST Complete assert";
356 break;
357 case Event::postCompleteDeAssert:
358 return "POST Complete de-assert";
359 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700360 case Event::powerButtonPressed:
361 return "power button pressed";
362 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700363 case Event::resetButtonPressed:
364 return "reset button pressed";
365 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700366 case Event::powerCycleTimerExpired:
367 return "power cycle timer expired";
368 break;
369 case Event::psPowerOKWatchdogTimerExpired:
370 return "power supply power OK watchdog timer expired";
371 break;
372 case Event::sioPowerGoodWatchdogTimerExpired:
373 return "SIO power good watchdog timer expired";
374 break;
375 case Event::gracefulPowerOffTimerExpired:
376 return "graceful power-off timer expired";
377 break;
378 case Event::powerOnRequest:
379 return "power-on request";
380 break;
381 case Event::powerOffRequest:
382 return "power-off request";
383 break;
384 case Event::powerCycleRequest:
385 return "power-cycle request";
386 break;
387 case Event::resetRequest:
388 return "reset request";
389 break;
390 case Event::gracefulPowerOffRequest:
391 return "graceful power-off request";
392 break;
393 case Event::gracefulPowerCycleRequest:
394 return "graceful power-cycle request";
395 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700396 case Event::warmResetDetected:
397 return "warm reset detected";
398 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700399 default:
400 return "unknown event: " + std::to_string(static_cast<int>(event));
401 break;
402 }
403}
404static void logEvent(const std::string_view stateHandler, const Event event)
405{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800406 lg2::info("{STATE_HANDLER}: {EVENT} event received", "STATE_HANDLER",
407 stateHandler, "EVENT", getEventName(event));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700408}
409
410// Power state handlers
411static void powerStateOn(const Event event);
412static void powerStateWaitForPSPowerOK(const Event event);
413static void powerStateWaitForSIOPowerGood(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700414static void powerStateOff(const Event event);
415static void powerStateTransitionToOff(const Event event);
416static void powerStateGracefulTransitionToOff(const Event event);
417static void powerStateCycleOff(const Event event);
418static void powerStateTransitionToCycleOff(const Event event);
419static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700420static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700421
422static std::function<void(const Event)> getPowerStateHandler(PowerState state)
423{
424 switch (state)
425 {
426 case PowerState::on:
427 return powerStateOn;
428 break;
429 case PowerState::waitForPSPowerOK:
430 return powerStateWaitForPSPowerOK;
431 break;
432 case PowerState::waitForSIOPowerGood:
433 return powerStateWaitForSIOPowerGood;
434 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700435 case PowerState::off:
436 return powerStateOff;
437 break;
438 case PowerState::transitionToOff:
439 return powerStateTransitionToOff;
440 break;
441 case PowerState::gracefulTransitionToOff:
442 return powerStateGracefulTransitionToOff;
443 break;
444 case PowerState::cycleOff:
445 return powerStateCycleOff;
446 break;
447 case PowerState::transitionToCycleOff:
448 return powerStateTransitionToCycleOff;
449 break;
450 case PowerState::gracefulTransitionToCycleOff:
451 return powerStateGracefulTransitionToCycleOff;
452 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700453 case PowerState::checkForWarmReset:
454 return powerStateCheckForWarmReset;
455 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700456 default:
Zev Weiss047bcb52020-08-20 21:28:11 +0000457 return nullptr;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700458 break;
459 }
460};
461
462static void sendPowerControlEvent(const Event event)
463{
464 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
465 if (handler == nullptr)
466 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800467 lg2::error("Failed to find handler for power state: {STATE}", "STATE",
468 static_cast<int>(powerState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700469 return;
470 }
471 handler(event);
472}
473
474static uint64_t getCurrentTimeMs()
475{
476 struct timespec time = {};
477
478 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
479 {
480 return 0;
481 }
482 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
483 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
484
485 return currentTimeMs;
486}
487
488static constexpr std::string_view getHostState(const PowerState state)
489{
490 switch (state)
491 {
492 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700493 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700494 case PowerState::gracefulTransitionToCycleOff:
495 return "xyz.openbmc_project.State.Host.HostState.Running";
496 break;
497 case PowerState::waitForPSPowerOK:
498 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700499 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700500 case PowerState::transitionToOff:
501 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700502 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700503 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700504 return "xyz.openbmc_project.State.Host.HostState.Off";
505 break;
506 default:
507 return "";
508 break;
509 }
510};
511static constexpr std::string_view getChassisState(const PowerState state)
512{
513 switch (state)
514 {
515 case PowerState::on:
516 case PowerState::transitionToOff:
517 case PowerState::gracefulTransitionToOff:
518 case PowerState::transitionToCycleOff:
519 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700520 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700521 return "xyz.openbmc_project.State.Chassis.PowerState.On";
522 break;
523 case PowerState::waitForPSPowerOK:
524 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700525 case PowerState::off:
526 case PowerState::cycleOff:
527 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
528 break;
529 default:
530 return "";
531 break;
532 }
533};
Naveen Moses117c34e2021-05-26 20:10:51 +0530534#ifdef CHASSIS_SYSTEM_RESET
535enum class SlotPowerState
536{
537 on,
538 off,
539};
540static SlotPowerState slotPowerState;
541static constexpr std::string_view getSlotState(const SlotPowerState state)
542{
543 switch (state)
544 {
545 case SlotPowerState::on:
546 return "xyz.openbmc_project.State.Chassis.PowerState.On";
547 break;
548 case SlotPowerState::off:
549 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
550 break;
551 default:
552 return "";
553 break;
554 }
555};
556static void setSlotPowerState(const SlotPowerState state)
557{
558 slotPowerState = state;
559 chassisSlotIface->set_property("CurrentPowerState",
560 std::string(getSlotState(slotPowerState)));
561 chassisSlotIface->set_property("LastStateChangeTime", getCurrentTimeMs());
562}
563#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700564static void savePowerState(const PowerState state)
565{
566 powerStateSaveTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -0700567 std::chrono::milliseconds(TimerMap["PowerOffSaveMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700568 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
569 if (ec)
570 {
571 // operation_aborted is expected if timer is canceled before
572 // completion.
573 if (ec != boost::asio::error::operation_aborted)
574 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800575 lg2::error("Power-state save async_wait failed: {ERROR_MSG}",
576 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700577 }
578 return;
579 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300580 appState.set(PersistentState::Params::PowerState,
581 std::string{getChassisState(state)});
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700582 });
583}
584static void setPowerState(const PowerState state)
585{
586 powerState = state;
587 logStateTransition(state);
588
589 hostIface->set_property("CurrentHostState",
590 std::string(getHostState(powerState)));
591
592 chassisIface->set_property("CurrentPowerState",
593 std::string(getChassisState(powerState)));
594 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
595
596 // Save the power state for the restore policy
597 savePowerState(state);
598}
599
600enum class RestartCause
601{
602 command,
603 resetButton,
604 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700605 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700606 powerPolicyOn,
607 powerPolicyRestore,
608 softReset,
609};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700610static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700611static std::string getRestartCause(RestartCause cause)
612{
613 switch (cause)
614 {
615 case RestartCause::command:
616 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
617 break;
618 case RestartCause::resetButton:
619 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
620 break;
621 case RestartCause::powerButton:
622 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
623 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700624 case RestartCause::watchdog:
625 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
626 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700627 case RestartCause::powerPolicyOn:
Jason M. Bills418ce112021-09-08 15:15:05 -0700628 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyAlwaysOn";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700629 break;
630 case RestartCause::powerPolicyRestore:
Jason M. Bills418ce112021-09-08 15:15:05 -0700631 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyPreviousState";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700632 break;
633 case RestartCause::softReset:
634 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
635 break;
636 default:
637 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
638 break;
639 }
640}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700641static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700642{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700643 // Add this to the set of causes for this restart
644 causeSet.insert(cause);
645}
646static void clearRestartCause()
647{
648 // Clear the set for the next restart
649 causeSet.clear();
650}
651static void setRestartCauseProperty(const std::string& cause)
652{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800653 lg2::info("RestartCause set to {RESTART_CAUSE}", "RESTART_CAUSE", cause);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700654 restartCauseIface->set_property("RestartCause", cause);
655}
Rashmi RV89f61312020-01-22 15:41:50 +0530656
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300657#ifdef USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +0530658static void resetACBootProperty()
659{
660 if ((causeSet.contains(RestartCause::command)) ||
661 (causeSet.contains(RestartCause::softReset)))
662 {
663 conn->async_method_call(
664 [](boost::system::error_code ec) {
665 if (ec)
666 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800667 lg2::error("failed to reset ACBoot property");
Rashmi RV89f61312020-01-22 15:41:50 +0530668 }
669 },
670 "xyz.openbmc_project.Settings",
671 "/xyz/openbmc_project/control/host0/ac_boot",
672 "org.freedesktop.DBus.Properties", "Set",
673 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
674 std::variant<std::string>{"False"});
675 }
676}
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300677#endif // USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +0530678
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700679static void setRestartCause()
680{
681 // Determine the actual restart cause based on the set of causes
682 std::string restartCause =
683 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
684 if (causeSet.contains(RestartCause::watchdog))
685 {
686 restartCause = getRestartCause(RestartCause::watchdog);
687 }
688 else if (causeSet.contains(RestartCause::command))
689 {
690 restartCause = getRestartCause(RestartCause::command);
691 }
692 else if (causeSet.contains(RestartCause::resetButton))
693 {
694 restartCause = getRestartCause(RestartCause::resetButton);
695 }
696 else if (causeSet.contains(RestartCause::powerButton))
697 {
698 restartCause = getRestartCause(RestartCause::powerButton);
699 }
700 else if (causeSet.contains(RestartCause::powerPolicyOn))
701 {
702 restartCause = getRestartCause(RestartCause::powerPolicyOn);
703 }
704 else if (causeSet.contains(RestartCause::powerPolicyRestore))
705 {
706 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
707 }
708 else if (causeSet.contains(RestartCause::softReset))
709 {
710 restartCause = getRestartCause(RestartCause::softReset);
711 }
712
713 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700714}
715
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700716static void systemPowerGoodFailedLog()
717{
718 sd_journal_send(
719 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
720 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
721 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700722 TimerMap["SioPowerGoodWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700723}
724
725static void psPowerOKFailedLog()
726{
727 sd_journal_send(
728 "MESSAGE=PowerControl: power supply power good failed to assert",
729 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
730 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700731 TimerMap["PsPowerOKWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700732}
733
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700734static void powerRestorePolicyLog()
735{
736 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
737 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
738 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
739}
740
741static void powerButtonPressLog()
742{
743 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
744 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
745 "OpenBMC.0.1.PowerButtonPressed", NULL);
746}
747
748static void resetButtonPressLog()
749{
750 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
751 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
752 "OpenBMC.0.1.ResetButtonPressed", NULL);
753}
754
755static void nmiButtonPressLog()
756{
757 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
758 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
759 "OpenBMC.0.1.NMIButtonPressed", NULL);
760}
761
762static void nmiDiagIntLog()
763{
764 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
765 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
766 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
767}
768
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300769PersistentState::PersistentState()
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700770{
771 // create the power control directory if it doesn't exist
772 std::error_code ec;
773 if (!(std::filesystem::create_directories(powerControlDir, ec)))
774 {
775 if (ec.value() != 0)
776 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800777 lg2::error("failed to create {DIR_NAME}: {ERROR_MSG}", "DIR_NAME",
778 powerControlDir.string(), "ERROR_MSG", ec.message());
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300779 throw std::runtime_error("Failed to create state directory");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700780 }
781 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300782
783 // read saved state, it's ok, if the file doesn't exists
784 std::ifstream appStateStream(powerControlDir / stateFile);
785 if (!appStateStream.is_open())
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700786 {
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300787 lg2::info("Cannot open state file \'{PATH}\'", "PATH",
788 std::string(powerControlDir / stateFile));
789 stateData = nlohmann::json({});
790 return;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700791 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300792 try
793 {
794 appStateStream >> stateData;
795 if (stateData.is_discarded())
796 {
797 lg2::info("Cannot parse state file \'{PATH}\'", "PATH",
798 std::string(powerControlDir / stateFile));
799 stateData = nlohmann::json({});
800 return;
801 }
802 }
803 catch (const std::exception& ex)
804 {
805 lg2::info("Cannot read state file \'{PATH}\'", "PATH",
806 std::string(powerControlDir / stateFile));
807 stateData = nlohmann::json({});
808 return;
809 }
810}
811PersistentState::~PersistentState()
812{
813 saveState();
814}
815const std::string PersistentState::get(Params parameter)
816{
817 auto val = stateData.find(getName(parameter));
818 if (val != stateData.end())
819 {
820 return val->get<std::string>();
821 }
822 return getDefault(parameter);
823}
824void PersistentState::set(Params parameter, const std::string& value)
825{
826 stateData[getName(parameter)] = value;
827 saveState();
828}
829
830const std::string PersistentState::getName(const Params parameter)
831{
832 switch (parameter)
833 {
834 case Params::PowerState:
835 return "PowerState";
836 }
837 return "";
838}
839const std::string PersistentState::getDefault(const Params parameter)
840{
841 switch (parameter)
842 {
843 case Params::PowerState:
844 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
845 }
846 return "";
847}
848void PersistentState::saveState()
849{
850 std::ofstream appStateStream(powerControlDir / stateFile, std::ios::trunc);
851 if (!appStateStream.is_open())
852 {
853 lg2::error("Cannot write state file \'{PATH}\'", "PATH",
854 std::string(powerControlDir / stateFile));
855 return;
856 }
857 appStateStream << stateData.dump(indentationSize);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700858}
859
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300860static constexpr char const* setingsService = "xyz.openbmc_project.Settings";
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300861static constexpr char const* powerRestorePolicyIface =
862 "xyz.openbmc_project.Control.Power.RestorePolicy";
863#ifdef USE_ACBOOT
864static constexpr char const* powerACBootObject =
865 "/xyz/openbmc_project/control/host0/ac_boot";
866static constexpr char const* powerACBootIface =
867 "xyz.openbmc_project.Common.ACBoot";
868#endif // USE_ACBOOT
869
870namespace match_rules = sdbusplus::bus::match::rules;
871
872static int powerRestoreConfigHandler(sd_bus_message* m, void* context,
873 sd_bus_error*)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700874{
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300875 if (context == nullptr || m == nullptr)
876 {
877 throw std::runtime_error("Invalid match");
878 }
Patrick Williams439b9c32022-07-22 19:26:53 -0500879 sdbusplus::message_t message(m);
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300880 PowerRestoreController* powerRestore =
881 static_cast<PowerRestoreController*>(context);
882
883 if (std::string(message.get_member()) == "InterfacesAdded")
884 {
885 sdbusplus::message::object_path path;
886 boost::container::flat_map<std::string, dbusPropertiesList> data;
887
888 message.read(path, data);
889
890 for (auto& [iface, properties] : data)
891 {
892 if ((iface == powerRestorePolicyIface)
893#ifdef USE_ACBOOT
894 || (iface == powerACBootIface)
895#endif // USE_ACBOOT
896 )
897 {
898 powerRestore->setProperties(properties);
899 }
900 }
901 }
902 else if (std::string(message.get_member()) == "PropertiesChanged")
903 {
904 std::string interfaceName;
905 dbusPropertiesList propertiesChanged;
906
907 message.read(interfaceName, propertiesChanged);
908
909 powerRestore->setProperties(propertiesChanged);
910 }
911 return 1;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700912}
913
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300914void PowerRestoreController::run()
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700915{
Karthikeyan Pasupathib38fe832022-07-19 19:53:38 +0530916 std::string powerRestorePolicyObject =
917 "/xyz/openbmc_project/control/host" + node + "/power_restore_policy";
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300918 powerRestorePolicyLog();
919 // this list only needs to be created once
920 if (matches.empty())
921 {
922 matches.emplace_back(
923 *conn,
924 match_rules::interfacesAdded() +
925 match_rules::argNpath(0, powerRestorePolicyObject) +
926 match_rules::sender(setingsService),
927 powerRestoreConfigHandler, this);
928#ifdef USE_ACBOOT
929 matches.emplace_back(*conn,
930 match_rules::interfacesAdded() +
931 match_rules::argNpath(0, powerACBootObject) +
932 match_rules::sender(setingsService),
933 powerRestoreConfigHandler, this);
934 matches.emplace_back(*conn,
935 match_rules::propertiesChanged(powerACBootObject,
936 powerACBootIface) +
937 match_rules::sender(setingsService),
938 powerRestoreConfigHandler, this);
939#endif // USE_ACBOOT
940 }
941
942 // Check if it's already on DBus
943 conn->async_method_call(
944 [this](boost::system::error_code ec,
945 const dbusPropertiesList properties) {
946 if (ec)
947 {
948 return;
949 }
950 setProperties(properties);
951 },
952 setingsService, powerRestorePolicyObject,
953 "org.freedesktop.DBus.Properties", "GetAll", powerRestorePolicyIface);
954
955#ifdef USE_ACBOOT
956 // Check if it's already on DBus
957 conn->async_method_call(
958 [this](boost::system::error_code ec,
959 const dbusPropertiesList properties) {
960 if (ec)
961 {
962 return;
963 }
964 setProperties(properties);
965 },
966 setingsService, powerACBootObject, "org.freedesktop.DBus.Properties",
967 "GetAll", powerACBootIface);
968#endif
969}
970
971void PowerRestoreController::setProperties(const dbusPropertiesList& props)
972{
973 for (auto& [property, propValue] : props)
974 {
975 if (property == "PowerRestorePolicy")
976 {
977 const std::string* value = std::get_if<std::string>(&propValue);
978 if (value == nullptr)
979 {
980 lg2::error("Unable to read Power Restore Policy");
981 continue;
982 }
983 powerRestorePolicy = *value;
984 }
985 else if (property == "PowerRestoreDelay")
986 {
987 const uint64_t* value = std::get_if<uint64_t>(&propValue);
988 if (value == nullptr)
989 {
990 lg2::error("Unable to read Power Restore Delay");
991 continue;
992 }
993 powerRestoreDelay = *value / 1000000; // usec to sec
994 }
995#ifdef USE_ACBOOT
996 else if (property == "ACBoot")
997 {
998 const std::string* value = std::get_if<std::string>(&propValue);
999 if (value == nullptr)
1000 {
1001 lg2::error("Unable to read AC Boot status");
1002 continue;
1003 }
1004 acBoot = *value;
1005 }
1006#endif // USE_ACBOOT
1007 }
1008 invokeIfReady();
1009}
1010
1011void PowerRestoreController::invokeIfReady()
1012{
1013 if ((powerRestorePolicy.empty()) || (powerRestoreDelay < 0))
1014 {
1015 return;
1016 }
1017#ifdef USE_ACBOOT
1018 if (acBoot.empty() || acBoot == "Unknown")
1019 {
1020 return;
1021 }
1022#endif
1023
1024 matches.clear();
1025 if (!timerFired)
1026 {
1027 // Calculate the delay from now to meet the requested delay
1028 // Subtract the approximate uboot time
1029 static constexpr const int ubootSeconds = 20;
1030 int delay = powerRestoreDelay - ubootSeconds;
1031 // Subtract the time since boot
1032 struct sysinfo info = {};
1033 if (sysinfo(&info) == 0)
1034 {
1035 delay -= info.uptime;
1036 }
1037
1038 if (delay > 0)
1039 {
1040 powerRestoreTimer.expires_after(std::chrono::seconds(delay));
1041 lg2::info("Power Restore delay of {DELAY} seconds started", "DELAY",
1042 delay);
1043 powerRestoreTimer.async_wait([this](const boost::system::error_code
1044 ec) {
1045 if (ec)
1046 {
1047 // operation_aborted is expected if timer is canceled before
1048 // completion.
1049 if (ec == boost::asio::error::operation_aborted)
1050 {
1051 return;
1052 }
1053 lg2::error(
1054 "power restore policy async_wait failed: {ERROR_MSG}",
1055 "ERROR_MSG", ec.message());
1056 }
1057 else
1058 {
1059 lg2::info("Power Restore delay timer expired");
1060 }
1061 invoke();
1062 });
1063 timerFired = true;
1064 }
1065 else
1066 {
1067 invoke();
1068 }
1069 }
1070}
1071
1072void PowerRestoreController::invoke()
1073{
1074 // we want to run Power Restore only once
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001075 if (policyInvoked)
1076 {
1077 return;
1078 }
1079 policyInvoked = true;
1080
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001081 lg2::info("Invoking Power Restore Policy {POLICY}", "POLICY",
1082 powerRestorePolicy);
1083 if (powerRestorePolicy ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001084 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
1085 {
1086 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001087 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001088 }
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001089 else if (powerRestorePolicy ==
Jason M. Bills418ce112021-09-08 15:15:05 -07001090 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore")
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001091 {
1092 if (wasPowerDropped())
1093 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001094 lg2::info("Power was dropped, restoring Host On state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001095 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001096 setRestartCauseProperty(
1097 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001098 }
1099 else
1100 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001101 lg2::info("No power drop, restoring Host Off state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001102 }
1103 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -07001104 // We're done with the previous power state for the restore policy, so store
1105 // the current state
1106 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001107}
1108
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001109bool PowerRestoreController::wasPowerDropped()
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001110{
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001111 std::string state = appState.get(PersistentState::Params::PowerState);
1112 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001113}
1114
Zev Weiss676ef2c2021-09-02 21:54:02 -05001115static void waitForGPIOEvent(const std::string& name,
1116 const std::function<void(bool)>& eventHandler,
1117 gpiod::line& line,
1118 boost::asio::posix::stream_descriptor& event)
1119{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001120 event.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1121 [&name, eventHandler, &line,
1122 &event](const boost::system::error_code ec) {
1123 if (ec)
1124 {
1125 lg2::error(
1126 "{GPIO_NAME} fd handler error: {ERROR_MSG}",
1127 "GPIO_NAME", name, "ERROR_MSG", ec.message());
1128 // TODO: throw here to force power-control to
1129 // restart?
1130 return;
1131 }
1132 gpiod::line_event line_event = line.event_read();
1133 eventHandler(line_event.event_type ==
1134 gpiod::line_event::RISING_EDGE);
1135 waitForGPIOEvent(name, eventHandler, line, event);
1136 });
Zev Weiss676ef2c2021-09-02 21:54:02 -05001137}
1138
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001139static bool requestGPIOEvents(
Zev Weiss676ef2c2021-09-02 21:54:02 -05001140 const std::string& name, const std::function<void(bool)>& handler,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001141 gpiod::line& gpioLine,
1142 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
1143{
1144 // Find the GPIO line
1145 gpioLine = gpiod::find_line(name);
1146 if (!gpioLine)
1147 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001148 lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001149 return false;
1150 }
1151
1152 try
1153 {
Andrei Kartashev3efcf372021-12-29 15:32:17 +03001154 gpioLine.request({appName, gpiod::line_request::EVENT_BOTH_EDGES, {}});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001155 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001156 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001157 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001158 lg2::error("Failed to request events for {GPIO_NAME}: {ERROR}",
1159 "GPIO_NAME", name, "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001160 return false;
1161 }
1162
1163 int gpioLineFd = gpioLine.event_get_fd();
1164 if (gpioLineFd < 0)
1165 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001166 lg2::error("Failed to get {GPIO_NAME} fd", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001167 return false;
1168 }
1169
1170 gpioEventDescriptor.assign(gpioLineFd);
1171
Zev Weiss676ef2c2021-09-02 21:54:02 -05001172 waitForGPIOEvent(name, handler, gpioLine, gpioEventDescriptor);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001173 return true;
1174}
1175
1176static bool setGPIOOutput(const std::string& name, const int value,
1177 gpiod::line& gpioLine)
1178{
1179 // Find the GPIO line
1180 gpioLine = gpiod::find_line(name);
1181 if (!gpioLine)
1182 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001183 lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001184 return false;
1185 }
1186
1187 // Request GPIO output to specified value
1188 try
1189 {
Andrei Kartashev3efcf372021-12-29 15:32:17 +03001190 gpioLine.request({appName, gpiod::line_request::DIRECTION_OUTPUT, {}},
1191 value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001192 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001193 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001194 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001195 lg2::error("Failed to request {GPIO_NAME} output: {ERROR}", "GPIO_NAME",
1196 name, "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001197 return false;
1198 }
1199
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001200 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1201 "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001202 return true;
1203}
1204
1205static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1206 const std::string& name, const int value,
1207 const int durationMs)
1208{
1209 // Set the masked GPIO line to the specified value
1210 maskedGPIOLine.set_value(value);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001211 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1212 "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001213 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001214 gpioAssertTimer.async_wait(
1215 [maskedGPIOLine, value, name](const boost::system::error_code ec) {
1216 // Set the masked GPIO line back to the opposite value
1217 maskedGPIOLine.set_value(!value);
1218 lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
1219 if (ec)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001220 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001221 // operation_aborted is expected if timer is canceled before
1222 // completion.
1223 if (ec != boost::asio::error::operation_aborted)
1224 {
1225 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1226 "GPIO_NAME", name, "ERROR_MSG", ec.message());
1227 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001228 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001229 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001230 return 0;
1231}
1232
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001233static int setGPIOOutputForMs(const ConfigData& config, const int value,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001234 const int durationMs)
1235{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001236 // If the requested GPIO is masked, use the mask line to set the output
1237 if (powerButtonMask && config.lineName == powerOutConfig.lineName)
1238 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001239 return setMaskedGPIOOutputForMs(powerButtonMask, config.lineName, value,
1240 durationMs);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001241 }
1242 if (resetButtonMask && config.lineName == resetOutConfig.lineName)
1243 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001244 return setMaskedGPIOOutputForMs(resetButtonMask, config.lineName, value,
1245 durationMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001246 }
1247
1248 // No mask set, so request and set the GPIO normally
1249 gpiod::line gpioLine;
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001250 if (!setGPIOOutput(config.lineName, value, gpioLine))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001251 {
1252 return -1;
1253 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001254 const std::string name = config.lineName;
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001255
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001256 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001257 gpioAssertTimer.async_wait(
1258 [gpioLine, value, name](const boost::system::error_code ec) {
1259 // Set the GPIO line back to the opposite value
1260 gpioLine.set_value(!value);
1261 lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
1262 if (ec)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001263 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001264 // operation_aborted is expected if timer is canceled before
1265 // completion.
1266 if (ec != boost::asio::error::operation_aborted)
1267 {
1268 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1269 "GPIO_NAME", name, "ERROR_MSG", ec.message());
1270 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001271 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001272 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001273 return 0;
1274}
1275
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001276static int assertGPIOForMs(const ConfigData& config, const int durationMs)
1277{
1278 return setGPIOOutputForMs(config, config.polarity, durationMs);
1279}
1280
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001281static void powerOn()
1282{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001283 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001284}
Naveen Moses117c34e2021-05-26 20:10:51 +05301285#ifdef CHASSIS_SYSTEM_RESET
1286static int slotPowerOn()
1287{
1288 if (power_control::slotPowerState != power_control::SlotPowerState::on)
1289 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001290
Naveen Moses117c34e2021-05-26 20:10:51 +05301291 slotPowerLine.set_value(1);
1292
1293 if (slotPowerLine.get_value() > 0)
1294 {
1295 setSlotPowerState(SlotPowerState::on);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001296 lg2::info("Slot Power is switched On\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301297 }
1298 else
1299 {
1300 return -1;
1301 }
1302 }
1303 else
1304 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001305 lg2::info("Slot Power is already in 'On' state\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301306 return -1;
1307 }
1308 return 0;
1309}
1310static int slotPowerOff()
1311{
1312 if (power_control::slotPowerState != power_control::SlotPowerState::off)
1313 {
1314 slotPowerLine.set_value(0);
1315
1316 if (!(slotPowerLine.get_value() > 0))
1317 {
1318 setSlotPowerState(SlotPowerState::off);
1319 setPowerState(PowerState::off);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001320 lg2::info("Slot Power is switched Off\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301321 }
1322 else
1323 {
1324 return -1;
1325 }
1326 }
1327 else
1328 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001329 lg2::info("Slot Power is already in 'Off' state\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301330 return -1;
1331 }
1332 return 0;
1333}
1334static void slotPowerCycle()
1335{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001336 lg2::info("Slot Power Cycle started\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301337 slotPowerOff();
1338 slotPowerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001339 std::chrono::milliseconds(TimerMap["SlotPowerCycleMs"]));
Naveen Moses117c34e2021-05-26 20:10:51 +05301340 slotPowerCycleTimer.async_wait([](const boost::system::error_code ec) {
1341 if (ec)
1342 {
1343 if (ec != boost::asio::error::operation_aborted)
1344 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001345 lg2::error(
1346 "Slot Power cycle timer async_wait failed: {ERROR_MSG}",
1347 "ERROR_MSG", ec.message());
Naveen Moses117c34e2021-05-26 20:10:51 +05301348 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001349 lg2::info("Slot Power cycle timer canceled\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301350 return;
1351 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001352 lg2::info("Slot Power cycle timer completed\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301353 slotPowerOn();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001354 lg2::info("Slot Power Cycle Completed\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301355 });
1356}
1357#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001358static void gracefulPowerOff()
1359{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001360 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001361}
1362
1363static void forcePowerOff()
1364{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001365 if (assertGPIOForMs(powerOutConfig, TimerMap["ForceOffPulseMs"]) < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001366 {
1367 return;
1368 }
1369
Jason M. Billsc6961b62021-10-21 14:08:02 -07001370 // If the force off timer expires, then the power-button override failed
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001371 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1372 if (ec)
1373 {
1374 // operation_aborted is expected if timer is canceled before
1375 // completion.
1376 if (ec != boost::asio::error::operation_aborted)
1377 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001378 lg2::error("Force power off async_wait failed: {ERROR_MSG}",
1379 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001380 }
1381 return;
1382 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001383
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001384 lg2::error("Power-button override failed. Not sure what to do now.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001385 });
1386}
1387
1388static void reset()
1389{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001390 assertGPIOForMs(resetOutConfig, TimerMap["ResetPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001391}
1392
1393static void gracefulPowerOffTimerStart()
1394{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001395 lg2::info("Graceful power-off timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001396 gracefulPowerOffTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001397 std::chrono::seconds(TimerMap["GracefulPowerOffS"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001398 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1399 if (ec)
1400 {
1401 // operation_aborted is expected if timer is canceled before
1402 // completion.
1403 if (ec != boost::asio::error::operation_aborted)
1404 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001405 lg2::error("Graceful power-off async_wait failed: {ERROR_MSG}",
1406 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001407 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001408 lg2::info("Graceful power-off timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001409 return;
1410 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001411 lg2::info("Graceful power-off timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001412 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1413 });
1414}
1415
1416static void powerCycleTimerStart()
1417{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001418 lg2::info("Power-cycle timer started");
Priyatharshan P70120512020-09-16 18:47:20 +05301419 powerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001420 std::chrono::milliseconds(TimerMap["PowerCycleMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001421 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1422 if (ec)
1423 {
1424 // operation_aborted is expected if timer is canceled before
1425 // completion.
1426 if (ec != boost::asio::error::operation_aborted)
1427 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001428 lg2::error("Power-cycle async_wait failed: {ERROR_MSG}",
1429 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001430 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001431 lg2::info("Power-cycle timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001432 return;
1433 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001434 lg2::info("Power-cycle timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001435 sendPowerControlEvent(Event::powerCycleTimerExpired);
1436 });
1437}
1438
1439static void psPowerOKWatchdogTimerStart()
1440{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001441 lg2::info("power supply power OK watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001442 psPowerOKWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001443 std::chrono::milliseconds(TimerMap["PsPowerOKWatchdogMs"]));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001444 psPowerOKWatchdogTimer.async_wait([](const boost::system::error_code ec) {
1445 if (ec)
1446 {
1447 // operation_aborted is expected if timer is canceled before
1448 // completion.
1449 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001450 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001451 lg2::error(
1452 "power supply power OK watchdog async_wait failed: {ERROR_MSG}",
1453 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001454 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001455 lg2::info("power supply power OK watchdog timer canceled");
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001456 return;
1457 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001458 lg2::info("power supply power OK watchdog timer expired");
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001459 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1460 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001461}
1462
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001463static void warmResetCheckTimerStart()
1464{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001465 lg2::info("Warm reset check timer started");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001466 warmResetCheckTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001467 std::chrono::milliseconds(TimerMap["WarmResetCheckMs"]));
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001468 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1469 if (ec)
1470 {
1471 // operation_aborted is expected if timer is canceled before
1472 // completion.
1473 if (ec != boost::asio::error::operation_aborted)
1474 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001475 lg2::error("Warm reset check async_wait failed: {ERROR_MSG}",
1476 "ERROR_MSG", ec.message());
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001477 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001478 lg2::info("Warm reset check timer canceled");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001479 return;
1480 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001481 lg2::info("Warm reset check timer completed");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001482 sendPowerControlEvent(Event::warmResetDetected);
1483 });
1484}
1485
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001486static void pohCounterTimerStart()
1487{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001488 lg2::info("POH timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001489 // Set the time-out as 1 hour, to align with POH command in ipmid
1490 pohCounterTimer.expires_after(std::chrono::hours(1));
1491 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1492 if (ec)
1493 {
1494 // operation_aborted is expected if timer is canceled before
1495 // completion.
1496 if (ec != boost::asio::error::operation_aborted)
1497 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001498 lg2::error("POH timer async_wait failed: {ERROR_MSG}",
1499 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001500 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001501 lg2::info("POH timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001502 return;
1503 }
1504
1505 if (getHostState(powerState) !=
1506 "xyz.openbmc_project.State.Host.HostState.Running")
1507 {
1508 return;
1509 }
1510
1511 conn->async_method_call(
1512 [](boost::system::error_code ec,
1513 const std::variant<uint32_t>& pohCounterProperty) {
1514 if (ec)
1515 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001516 lg2::error("error getting poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001517 return;
1518 }
1519 const uint32_t* pohCounter =
1520 std::get_if<uint32_t>(&pohCounterProperty);
1521 if (pohCounter == nullptr)
1522 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001523 lg2::error("unable to read poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001524 return;
1525 }
1526
1527 conn->async_method_call(
1528 [](boost::system::error_code ec) {
1529 if (ec)
1530 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001531 lg2::error("failed to set poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001532 }
1533 },
1534 "xyz.openbmc_project.Settings",
1535 "/xyz/openbmc_project/state/chassis0",
1536 "org.freedesktop.DBus.Properties", "Set",
1537 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1538 std::variant<uint32_t>(*pohCounter + 1));
1539 },
1540 "xyz.openbmc_project.Settings",
1541 "/xyz/openbmc_project/state/chassis0",
1542 "org.freedesktop.DBus.Properties", "Get",
1543 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1544
1545 pohCounterTimerStart();
1546 });
1547}
1548
1549static void currentHostStateMonitor()
1550{
Yong Li8d660212019-12-27 10:18:10 +08001551 if (getHostState(powerState) ==
1552 "xyz.openbmc_project.State.Host.HostState.Running")
1553 {
1554 pohCounterTimerStart();
1555 // Clear the restart cause set for the next restart
1556 clearRestartCause();
1557 }
1558 else
1559 {
1560 pohCounterTimer.cancel();
1561 // Set the restart cause set for this restart
1562 setRestartCause();
1563 }
1564
Patrick Williams439b9c32022-07-22 19:26:53 -05001565 static auto match = sdbusplus::bus::match_t(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001566 *conn,
1567 "type='signal',member='PropertiesChanged', "
1568 "interface='org.freedesktop.DBus.Properties', "
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001569 "arg0='xyz.openbmc_project.State.Host'",
Patrick Williams439b9c32022-07-22 19:26:53 -05001570 [](sdbusplus::message_t& message) {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001571 std::string intfName;
1572 std::map<std::string, std::variant<std::string>> properties;
1573
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001574 try
1575 {
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001576 message.read(intfName, properties);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001577 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05001578 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001579 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001580 lg2::error("Unable to read host state: {ERROR}", "ERROR", e);
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001581 return;
1582 }
1583 if (properties.empty())
1584 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001585 lg2::error("ERROR: Empty PropertiesChanged signal received");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001586 return;
1587 }
1588
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001589 // We only want to check for CurrentHostState
1590 if (properties.begin()->first != "CurrentHostState")
1591 {
1592 return;
1593 }
1594 std::string* currentHostState =
1595 std::get_if<std::string>(&(properties.begin()->second));
1596 if (currentHostState == nullptr)
1597 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001598 lg2::error("{PROPERTY} property invalid", "PROPERTY",
1599 properties.begin()->first);
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001600 return;
1601 }
1602
1603 if (*currentHostState ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001604 "xyz.openbmc_project.State.Host.HostState.Running")
1605 {
1606 pohCounterTimerStart();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001607 // Clear the restart cause set for the next restart
1608 clearRestartCause();
Yong Li8d660212019-12-27 10:18:10 +08001609 sd_journal_send("MESSAGE=Host system DC power is on",
1610 "PRIORITY=%i", LOG_INFO,
1611 "REDFISH_MESSAGE_ID=%s",
1612 "OpenBMC.0.1.DCPowerOn", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001613 }
1614 else
1615 {
1616 pohCounterTimer.cancel();
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301617 // POST_COMPLETE GPIO event is not working in some platforms
1618 // when power state is changed to OFF. This resulted in
1619 // 'OperatingSystemState' to stay at 'Standby', even though
1620 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1621 // if HostState is trurned to OFF.
Tim Lee86239182021-12-23 11:46:01 +08001622 setOperatingSystemState(OperatingSystemStateStage::Inactive);
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301623
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001624 // Set the restart cause set for this restart
1625 setRestartCause();
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001626#ifdef USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +05301627 resetACBootProperty();
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001628#endif // USE_ACBOOT
Yong Li8d660212019-12-27 10:18:10 +08001629 sd_journal_send("MESSAGE=Host system DC power is off",
1630 "PRIORITY=%i", LOG_INFO,
1631 "REDFISH_MESSAGE_ID=%s",
1632 "OpenBMC.0.1.DCPowerOff", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001633 }
1634 });
1635}
1636
1637static void sioPowerGoodWatchdogTimerStart()
1638{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001639 lg2::info("SIO power good watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001640 sioPowerGoodWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001641 std::chrono::milliseconds(TimerMap["SioPowerGoodWatchdogMs"]));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001642 sioPowerGoodWatchdogTimer.async_wait([](const boost::system::error_code
1643 ec) {
1644 if (ec)
1645 {
1646 // operation_aborted is expected if timer is canceled before
1647 // completion.
1648 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001649 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001650 lg2::error(
1651 "SIO power good watchdog async_wait failed: {ERROR_MSG}",
1652 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001653 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001654 lg2::info("SIO power good watchdog timer canceled");
1655 return;
1656 }
1657 lg2::info("SIO power good watchdog timer completed");
1658 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1659 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001660}
1661
1662static void powerStateOn(const Event event)
1663{
1664 logEvent(__FUNCTION__, event);
1665 switch (event)
1666 {
1667 case Event::psPowerOKDeAssert:
1668 setPowerState(PowerState::off);
1669 // DC power is unexpectedly lost, beep
1670 beep(beepPowerFail);
1671 break;
1672 case Event::sioS5Assert:
1673 setPowerState(PowerState::transitionToOff);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001674 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001675 break;
Jason M. Billsfb957332021-01-28 13:18:46 -08001676#if USE_PLT_RST
1677 case Event::pltRstAssert:
1678#else
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001679 case Event::postCompleteDeAssert:
Jason M. Billsfb957332021-01-28 13:18:46 -08001680#endif
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001681 setPowerState(PowerState::checkForWarmReset);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001682 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001683 warmResetCheckTimerStart();
1684 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001685 case Event::powerButtonPressed:
1686 setPowerState(PowerState::gracefulTransitionToOff);
1687 gracefulPowerOffTimerStart();
1688 break;
1689 case Event::powerOffRequest:
1690 setPowerState(PowerState::transitionToOff);
1691 forcePowerOff();
1692 break;
1693 case Event::gracefulPowerOffRequest:
1694 setPowerState(PowerState::gracefulTransitionToOff);
1695 gracefulPowerOffTimerStart();
1696 gracefulPowerOff();
1697 break;
1698 case Event::powerCycleRequest:
1699 setPowerState(PowerState::transitionToCycleOff);
1700 forcePowerOff();
1701 break;
1702 case Event::gracefulPowerCycleRequest:
1703 setPowerState(PowerState::gracefulTransitionToCycleOff);
1704 gracefulPowerOffTimerStart();
1705 gracefulPowerOff();
1706 break;
1707 case Event::resetRequest:
1708 reset();
1709 break;
1710 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001711 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001712 break;
1713 }
1714}
1715
1716static void powerStateWaitForPSPowerOK(const Event event)
1717{
1718 logEvent(__FUNCTION__, event);
1719 switch (event)
1720 {
1721 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301722 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001723 // Cancel any GPIO assertions held during the transition
1724 gpioAssertTimer.cancel();
1725 psPowerOKWatchdogTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301726 if (sioEnabled == true)
1727 {
1728 sioPowerGoodWatchdogTimerStart();
1729 setPowerState(PowerState::waitForSIOPowerGood);
1730 }
1731 else
1732 {
1733 setPowerState(PowerState::on);
1734 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001735 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301736 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001737 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001738 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001739 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001740 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001741 case Event::sioPowerGoodAssert:
1742 psPowerOKWatchdogTimer.cancel();
1743 setPowerState(PowerState::on);
1744 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001745 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001746 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001747 break;
1748 }
1749}
1750
1751static void powerStateWaitForSIOPowerGood(const Event event)
1752{
1753 logEvent(__FUNCTION__, event);
1754 switch (event)
1755 {
1756 case Event::sioPowerGoodAssert:
1757 sioPowerGoodWatchdogTimer.cancel();
1758 setPowerState(PowerState::on);
1759 break;
1760 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001761 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001762 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001763 break;
1764 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001765 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001766 break;
1767 }
1768}
1769
1770static void powerStateOff(const Event event)
1771{
1772 logEvent(__FUNCTION__, event);
1773 switch (event)
1774 {
1775 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301776 {
1777 if (sioEnabled == true)
1778 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001779 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301780 setPowerState(PowerState::waitForSIOPowerGood);
1781 }
1782 else
1783 {
1784 setPowerState(PowerState::on);
1785 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001786 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301787 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001788 case Event::sioS5DeAssert:
1789 setPowerState(PowerState::waitForPSPowerOK);
1790 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001791 case Event::sioPowerGoodAssert:
1792 setPowerState(PowerState::on);
1793 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001794 case Event::powerButtonPressed:
1795 psPowerOKWatchdogTimerStart();
1796 setPowerState(PowerState::waitForPSPowerOK);
1797 break;
1798 case Event::powerOnRequest:
1799 psPowerOKWatchdogTimerStart();
1800 setPowerState(PowerState::waitForPSPowerOK);
1801 powerOn();
1802 break;
1803 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001804 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001805 break;
1806 }
1807}
1808
1809static void powerStateTransitionToOff(const Event event)
1810{
1811 logEvent(__FUNCTION__, event);
1812 switch (event)
1813 {
1814 case Event::psPowerOKDeAssert:
1815 // Cancel any GPIO assertions held during the transition
1816 gpioAssertTimer.cancel();
1817 setPowerState(PowerState::off);
1818 break;
1819 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001820 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001821 break;
1822 }
1823}
1824
1825static void powerStateGracefulTransitionToOff(const Event event)
1826{
1827 logEvent(__FUNCTION__, event);
1828 switch (event)
1829 {
1830 case Event::psPowerOKDeAssert:
1831 gracefulPowerOffTimer.cancel();
1832 setPowerState(PowerState::off);
1833 break;
1834 case Event::gracefulPowerOffTimerExpired:
1835 setPowerState(PowerState::on);
1836 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001837 case Event::powerOffRequest:
1838 gracefulPowerOffTimer.cancel();
1839 setPowerState(PowerState::transitionToOff);
1840 forcePowerOff();
1841 break;
1842 case Event::powerCycleRequest:
1843 gracefulPowerOffTimer.cancel();
1844 setPowerState(PowerState::transitionToCycleOff);
1845 forcePowerOff();
1846 break;
1847 case Event::resetRequest:
1848 gracefulPowerOffTimer.cancel();
1849 setPowerState(PowerState::on);
1850 reset();
1851 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001852 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001853 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001854 break;
1855 }
1856}
1857
1858static void powerStateCycleOff(const Event event)
1859{
1860 logEvent(__FUNCTION__, event);
1861 switch (event)
1862 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001863 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301864 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001865 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301866 if (sioEnabled == true)
1867 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001868 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301869 setPowerState(PowerState::waitForSIOPowerGood);
1870 }
1871 else
1872 {
1873 setPowerState(PowerState::on);
1874 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001875 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301876 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001877 case Event::sioS5DeAssert:
1878 powerCycleTimer.cancel();
1879 setPowerState(PowerState::waitForPSPowerOK);
1880 break;
1881 case Event::powerButtonPressed:
1882 powerCycleTimer.cancel();
1883 psPowerOKWatchdogTimerStart();
1884 setPowerState(PowerState::waitForPSPowerOK);
1885 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001886 case Event::powerCycleTimerExpired:
1887 psPowerOKWatchdogTimerStart();
1888 setPowerState(PowerState::waitForPSPowerOK);
1889 powerOn();
1890 break;
1891 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001892 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001893 break;
1894 }
1895}
1896
1897static void powerStateTransitionToCycleOff(const Event event)
1898{
1899 logEvent(__FUNCTION__, event);
1900 switch (event)
1901 {
1902 case Event::psPowerOKDeAssert:
1903 // Cancel any GPIO assertions held during the transition
1904 gpioAssertTimer.cancel();
1905 setPowerState(PowerState::cycleOff);
1906 powerCycleTimerStart();
1907 break;
1908 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001909 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001910 break;
1911 }
1912}
1913
1914static void powerStateGracefulTransitionToCycleOff(const Event event)
1915{
1916 logEvent(__FUNCTION__, event);
1917 switch (event)
1918 {
1919 case Event::psPowerOKDeAssert:
1920 gracefulPowerOffTimer.cancel();
1921 setPowerState(PowerState::cycleOff);
1922 powerCycleTimerStart();
1923 break;
1924 case Event::gracefulPowerOffTimerExpired:
1925 setPowerState(PowerState::on);
1926 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001927 case Event::powerOffRequest:
1928 gracefulPowerOffTimer.cancel();
1929 setPowerState(PowerState::transitionToOff);
1930 forcePowerOff();
1931 break;
1932 case Event::powerCycleRequest:
1933 gracefulPowerOffTimer.cancel();
1934 setPowerState(PowerState::transitionToCycleOff);
1935 forcePowerOff();
1936 break;
1937 case Event::resetRequest:
1938 gracefulPowerOffTimer.cancel();
1939 setPowerState(PowerState::on);
1940 reset();
1941 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001942 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001943 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001944 break;
1945 }
1946}
1947
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001948static void powerStateCheckForWarmReset(const Event event)
1949{
1950 logEvent(__FUNCTION__, event);
1951 switch (event)
1952 {
1953 case Event::sioS5Assert:
1954 warmResetCheckTimer.cancel();
1955 setPowerState(PowerState::transitionToOff);
1956 break;
1957 case Event::warmResetDetected:
1958 setPowerState(PowerState::on);
1959 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001960 case Event::psPowerOKDeAssert:
1961 warmResetCheckTimer.cancel();
1962 setPowerState(PowerState::off);
1963 // DC power is unexpectedly lost, beep
1964 beep(beepPowerFail);
1965 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001966 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001967 lg2::info("No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001968 break;
1969 }
1970}
1971
Zev Weiss584aa132021-09-02 19:21:52 -05001972static void psPowerOKHandler(bool state)
1973{
1974 Event powerControlEvent =
1975 state ? Event::psPowerOKAssert : Event::psPowerOKDeAssert;
1976 sendPowerControlEvent(powerControlEvent);
1977}
1978
Zev Weiss584aa132021-09-02 19:21:52 -05001979static void sioPowerGoodHandler(bool state)
1980{
1981 Event powerControlEvent =
1982 state ? Event::sioPowerGoodAssert : Event::sioPowerGoodDeAssert;
1983 sendPowerControlEvent(powerControlEvent);
1984}
1985
Zev Weiss584aa132021-09-02 19:21:52 -05001986static void sioOnControlHandler(bool state)
1987{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001988 lg2::info("SIO_ONCONTROL value changed: {VALUE}", "VALUE",
1989 static_cast<int>(state));
Zev Weiss584aa132021-09-02 19:21:52 -05001990}
1991
Zev Weiss584aa132021-09-02 19:21:52 -05001992static void sioS5Handler(bool state)
1993{
1994 Event powerControlEvent = state ? Event::sioS5DeAssert : Event::sioS5Assert;
1995 sendPowerControlEvent(powerControlEvent);
1996}
1997
Zev Weiss584aa132021-09-02 19:21:52 -05001998static void powerButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001999{
Zev Weiss584aa132021-09-02 19:21:52 -05002000 powerButtonIface->set_property("ButtonPressed", !state);
2001 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002002 {
2003 powerButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002004 if (!powerButtonMask)
2005 {
2006 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002007 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002008 }
2009 else
2010 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002011 lg2::info("power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002012 }
2013 }
Zev Weiss584aa132021-09-02 19:21:52 -05002014}
2015
Zev Weiss584aa132021-09-02 19:21:52 -05002016static void resetButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002017{
Zev Weiss584aa132021-09-02 19:21:52 -05002018 resetButtonIface->set_property("ButtonPressed", !state);
2019 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002020 {
2021 resetButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002022 if (!resetButtonMask)
2023 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002024 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002025 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002026 }
2027 else
2028 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002029 lg2::info("reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002030 }
2031 }
Zev Weiss584aa132021-09-02 19:21:52 -05002032}
2033
Vijay Khemka04175c22020-10-09 14:28:11 -07002034#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002035static constexpr auto systemdBusname = "org.freedesktop.systemd1";
2036static constexpr auto systemdPath = "/org/freedesktop/systemd1";
2037static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
2038static constexpr auto systemTargetName = "chassis-system-reset.target";
2039
2040void systemReset()
2041{
2042 conn->async_method_call(
2043 [](boost::system::error_code ec) {
2044 if (ec)
2045 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002046 lg2::error("Failed to call chassis system reset: {ERR}", "ERR",
2047 ec.message());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002048 }
2049 },
2050 systemdBusname, systemdPath, systemdInterface, "StartUnit",
2051 systemTargetName, "replace");
2052}
Vijay Khemka04175c22020-10-09 14:28:11 -07002053#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002054
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002055static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002056{
2057 conn->async_method_call(
2058 [](boost::system::error_code ec) {
2059 if (ec)
2060 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002061 lg2::error("failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002062 }
2063 },
Chen Yugang303bd582019-11-01 08:45:06 +08002064 "xyz.openbmc_project.Settings",
2065 "/xyz/openbmc_project/Chassis/Control/NMISource",
2066 "org.freedesktop.DBus.Properties", "Set",
2067 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
2068 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002069}
2070
2071static void nmiReset(void)
2072{
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002073 const static constexpr int nmiOutPulseTimeMs = 200;
2074
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002075 lg2::info("NMI out action");
Ping Guo8643c792022-05-18 08:32:00 +08002076 nmiOutLine.set_value(!nmiOutConfig.polarity);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002077 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME",
Ping Guo8643c792022-05-18 08:32:00 +08002078 nmiOutConfig.lineName, "GPIO_VALUE", !nmiOutConfig.polarity);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002079 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2080 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2081 // restore the NMI_OUT GPIO line back to the opposite value
Ping Guo8643c792022-05-18 08:32:00 +08002082 nmiOutLine.set_value(nmiOutConfig.polarity);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002083 lg2::info("{GPIO_NAME} released", "GPIO_NAME", nmiOutConfig.lineName);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002084 if (ec)
2085 {
2086 // operation_aborted is expected if timer is canceled before
2087 // completion.
2088 if (ec != boost::asio::error::operation_aborted)
2089 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002090 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
2091 "GPIO_NAME", nmiOutConfig.lineName, "ERROR_MSG",
2092 ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002093 }
2094 }
2095 });
2096 // log to redfish
2097 nmiDiagIntLog();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002098 lg2::info("NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002099 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002100 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002101}
2102
2103static void nmiSourcePropertyMonitor(void)
2104{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002105 lg2::info("NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002106
Patrick Williams439b9c32022-07-22 19:26:53 -05002107 static std::unique_ptr<sdbusplus::bus::match_t> nmiSourceMatch =
2108 std::make_unique<sdbusplus::bus::match_t>(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002109 *conn,
2110 "type='signal',interface='org.freedesktop.DBus.Properties',"
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002111 "member='PropertiesChanged',"
2112 "arg0namespace='xyz.openbmc_project.Chassis.Control.NMISource'",
Patrick Williams439b9c32022-07-22 19:26:53 -05002113 [](sdbusplus::message_t& msg) {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002114 std::string interfaceName;
2115 boost::container::flat_map<std::string,
2116 std::variant<bool, std::string>>
2117 propertiesChanged;
2118 std::string state;
2119 bool value = true;
2120 try
2121 {
2122 msg.read(interfaceName, propertiesChanged);
2123 if (propertiesChanged.begin()->first == "Enabled")
2124 {
2125 value =
2126 std::get<bool>(propertiesChanged.begin()->second);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002127 lg2::info(
2128 "NMI Enabled propertiesChanged value: {VALUE}",
2129 "VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002130 nmiEnabled = value;
2131 if (nmiEnabled)
2132 {
2133 nmiReset();
2134 }
2135 }
2136 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002137 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002138 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002139 lg2::error("Unable to read NMI source: {ERROR}", "ERROR",
2140 e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002141 return;
2142 }
2143 });
2144}
2145
2146static void setNmiSource()
2147{
2148 conn->async_method_call(
2149 [](boost::system::error_code ec) {
2150 if (ec)
2151 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002152 lg2::error("failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002153 }
2154 },
Chen Yugang303bd582019-11-01 08:45:06 +08002155 "xyz.openbmc_project.Settings",
2156 "/xyz/openbmc_project/Chassis/Control/NMISource",
2157 "org.freedesktop.DBus.Properties", "Set",
2158 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
Jason M. Bills418ce112021-09-08 15:15:05 -07002159 std::variant<std::string>{
2160 "xyz.openbmc_project.Chassis.Control.NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002161 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002162 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002163}
2164
Zev Weiss584aa132021-09-02 19:21:52 -05002165static void nmiButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002166{
Zev Weiss584aa132021-09-02 19:21:52 -05002167 nmiButtonIface->set_property("ButtonPressed", !state);
2168 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002169 {
2170 nmiButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002171 if (nmiButtonMasked)
2172 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002173 lg2::info("NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002174 }
2175 else
2176 {
2177 setNmiSource();
2178 }
2179 }
Zev Weiss584aa132021-09-02 19:21:52 -05002180}
2181
Zev Weiss584aa132021-09-02 19:21:52 -05002182static void idButtonHandler(bool state)
2183{
2184 idButtonIface->set_property("ButtonPressed", !state);
2185}
2186
Jason M. Billsfb957332021-01-28 13:18:46 -08002187static void pltRstHandler(bool pltRst)
2188{
2189 if (pltRst)
2190 {
2191 sendPowerControlEvent(Event::pltRstDeAssert);
2192 }
2193 else
2194 {
2195 sendPowerControlEvent(Event::pltRstAssert);
2196 }
2197}
2198
Patrick Williams439b9c32022-07-22 19:26:53 -05002199[[maybe_unused]] static void hostMiscHandler(sdbusplus::message_t& msg)
Jason M. Billsfb957332021-01-28 13:18:46 -08002200{
2201 std::string interfaceName;
2202 boost::container::flat_map<std::string, std::variant<bool>>
2203 propertiesChanged;
Jason M. Billsfb957332021-01-28 13:18:46 -08002204 try
2205 {
2206 msg.read(interfaceName, propertiesChanged);
2207 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002208 catch (const std::exception& e)
Jason M. Billsfb957332021-01-28 13:18:46 -08002209 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002210 lg2::error("Unable to read Host Misc status: {ERROR}", "ERROR", e);
Jason M. Billsfb957332021-01-28 13:18:46 -08002211 return;
2212 }
2213 if (propertiesChanged.empty())
2214 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002215 lg2::error("ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002216 return;
2217 }
2218
2219 for (auto& [property, value] : propertiesChanged)
2220 {
2221 if (property == "ESpiPlatformReset")
2222 {
2223 bool* pltRst = std::get_if<bool>(&value);
2224 if (pltRst == nullptr)
2225 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002226 lg2::error("{PROPERTY} property invalid", "PROPERTY", property);
Jason M. Billsfb957332021-01-28 13:18:46 -08002227 return;
2228 }
2229 pltRstHandler(*pltRst);
2230 }
2231 }
2232}
2233
Zev Weiss584aa132021-09-02 19:21:52 -05002234static void postCompleteHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002235{
Zev Weiss584aa132021-09-02 19:21:52 -05002236 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002237 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002238 sendPowerControlEvent(Event::postCompleteAssert);
Tim Lee86239182021-12-23 11:46:01 +08002239 setOperatingSystemState(OperatingSystemStateStage::Standby);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002240 }
2241 else
2242 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002243 sendPowerControlEvent(Event::postCompleteDeAssert);
Tim Lee86239182021-12-23 11:46:01 +08002244 setOperatingSystemState(OperatingSystemStateStage::Inactive);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002245 }
Zev Weiss584aa132021-09-02 19:21:52 -05002246}
2247
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302248static int loadConfigValues()
2249{
2250 const std::string configFilePath =
2251 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2252 ".json";
2253 std::ifstream configFile(configFilePath.c_str());
2254 if (!configFile.is_open())
2255 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002256 lg2::error("loadConfigValues: Cannot open config path \'{PATH}\'",
2257 "PATH", configFilePath);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302258 return -1;
2259 }
Zev Weiss1aa08b22021-09-15 17:06:20 -05002260 auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302261
Priyatharshan P70120512020-09-16 18:47:20 +05302262 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302263 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002264 lg2::error("Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302265 return -1;
2266 }
Priyatharshan P70120512020-09-16 18:47:20 +05302267 auto gpios = jsonData["gpio_configs"];
2268 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302269
Priyatharshan P70120512020-09-16 18:47:20 +05302270 ConfigData* tempGpioData;
2271
2272 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302273 {
Priyatharshan P70120512020-09-16 18:47:20 +05302274 if (!gpioConfig.contains("Name"))
2275 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002276 lg2::error("The 'Name' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302277 return -1;
2278 }
2279
2280 // Iterate through the powersignal map to check if the gpio json config
2281 // entry is valid
2282 std::string gpioName = gpioConfig["Name"];
2283 auto signalMapIter = powerSignalMap.find(gpioName);
2284 if (signalMapIter == powerSignalMap.end())
2285 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002286 lg2::error(
2287 "{GPIO_NAME} is not a recognized power-control signal name",
2288 "GPIO_NAME", gpioName);
Priyatharshan P70120512020-09-16 18:47:20 +05302289 return -1;
2290 }
2291
2292 // assign the power signal name to the corresponding structure reference
2293 // from map then fillup the structure with coressponding json config
2294 // value
2295 tempGpioData = signalMapIter->second;
2296 tempGpioData->name = gpioName;
2297
2298 if (!gpioConfig.contains("Type"))
2299 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002300 lg2::error("The \'Type\' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302301 return -1;
2302 }
2303
2304 std::string signalType = gpioConfig["Type"];
2305 if (signalType == "GPIO")
2306 {
2307 tempGpioData->type = ConfigType::GPIO;
2308 }
2309 else if (signalType == "DBUS")
2310 {
2311 tempGpioData->type = ConfigType::DBUS;
2312 }
2313 else
2314 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002315 lg2::error("{TYPE} is not a recognized power-control signal type",
2316 "TYPE", signalType);
Priyatharshan P70120512020-09-16 18:47:20 +05302317 return -1;
2318 }
2319
2320 if (tempGpioData->type == ConfigType::GPIO)
2321 {
2322 if (gpioConfig.contains("LineName"))
2323 {
2324 tempGpioData->lineName = gpioConfig["LineName"];
2325 }
2326 else
2327 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002328 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002329 "The \'LineName\' field must be defined for GPIO configuration");
Priyatharshan P70120512020-09-16 18:47:20 +05302330 return -1;
2331 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002332 if (gpioConfig.contains("Polarity"))
2333 {
2334 std::string polarity = gpioConfig["Polarity"];
2335 if (polarity == "ActiveLow")
2336 {
2337 tempGpioData->polarity = false;
2338 }
2339 else if (polarity == "ActiveHigh")
2340 {
2341 tempGpioData->polarity = true;
2342 }
2343 else
2344 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002345 lg2::error(
2346 "Polarity defined but not properly setup. Please only ActiveHigh or ActiveLow. Currently set to {POLARITY}",
2347 "POLARITY", polarity);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002348 return -1;
2349 }
2350 }
2351 else
2352 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002353 lg2::error("Polarity field not found for {GPIO_NAME}",
2354 "GPIO_NAME", tempGpioData->lineName);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002355 return -1;
2356 }
Priyatharshan P70120512020-09-16 18:47:20 +05302357 }
2358 else
2359 {
2360 // if dbus based gpio config is defined read and update the dbus
2361 // params corresponding to the gpio config instance
2362 for (auto& [key, dbusParamName] : dbusParams)
2363 {
Logananth Sundararaja4308042021-10-20 11:52:05 +05302364 if (!gpioConfig.contains(dbusParamName))
Priyatharshan P70120512020-09-16 18:47:20 +05302365 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002366 lg2::error(
2367 "The {DBUS_NAME} field must be defined for Dbus configuration ",
2368 "DBUS_NAME", dbusParamName);
Priyatharshan P70120512020-09-16 18:47:20 +05302369 return -1;
2370 }
2371 }
Logananth Sundararaja4308042021-10-20 11:52:05 +05302372 tempGpioData->dbusName =
2373 gpioConfig[dbusParams[DbusConfigType::name]];
2374 tempGpioData->path = gpioConfig[dbusParams[DbusConfigType::path]];
Priyatharshan P70120512020-09-16 18:47:20 +05302375 tempGpioData->interface =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302376 gpioConfig[dbusParams[DbusConfigType::interface]];
Priyatharshan P70120512020-09-16 18:47:20 +05302377 tempGpioData->lineName =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302378 gpioConfig[dbusParams[DbusConfigType::property]];
Priyatharshan P70120512020-09-16 18:47:20 +05302379 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302380 }
2381
Priyatharshan P70120512020-09-16 18:47:20 +05302382 // read and store the timer values from json config to Timer Map
2383 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302384 {
Priyatharshan P70120512020-09-16 18:47:20 +05302385 if (timers.contains(key.c_str()))
2386 {
2387 timerValue = timers[key.c_str()];
2388 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302389 }
2390
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302391 return 0;
2392}
Zev Weissa8f116a2021-09-01 21:08:30 -05002393
Patrick Williams439b9c32022-07-22 19:26:53 -05002394static bool getDbusMsgGPIOState(sdbusplus::message_t& msg,
Zev Weissa8f116a2021-09-01 21:08:30 -05002395 const std::string& lineName, bool& value)
2396{
2397 std::string thresholdInterface;
2398 std::string event;
2399 boost::container::flat_map<std::string, std::variant<bool>>
2400 propertiesChanged;
2401 try
2402 {
2403 msg.read(thresholdInterface, propertiesChanged);
2404 if (propertiesChanged.empty())
2405 {
2406 return false;
2407 }
2408
2409 event = propertiesChanged.begin()->first;
2410 if (event.empty() || event != lineName)
2411 {
2412 return false;
2413 }
2414
2415 value = std::get<bool>(propertiesChanged.begin()->second);
2416 return true;
2417 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002418 catch (const std::exception& e)
Zev Weissa8f116a2021-09-01 21:08:30 -05002419 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002420 lg2::error(
2421 "exception while reading dbus property \'{DBUS_NAME}\': {ERROR}",
2422 "DBUS_NAME", lineName, "ERROR", e);
Zev Weissa8f116a2021-09-01 21:08:30 -05002423 return false;
2424 }
2425}
2426
Patrick Williams439b9c32022-07-22 19:26:53 -05002427static sdbusplus::bus::match_t
Zev Weissa8f116a2021-09-01 21:08:30 -05002428 dbusGPIOMatcher(const ConfigData& cfg, std::function<void(bool)> onMatch)
2429{
Patrick Williams439b9c32022-07-22 19:26:53 -05002430 auto pulseEventMatcherCallback = [&cfg,
2431 onMatch](sdbusplus::message_t& msg) {
2432 bool value = false;
2433 if (!getDbusMsgGPIOState(msg, cfg.lineName, value))
2434 {
2435 return;
2436 }
2437 onMatch(value);
2438 };
Zev Weissa8f116a2021-09-01 21:08:30 -05002439
Patrick Williams439b9c32022-07-22 19:26:53 -05002440 return sdbusplus::bus::match_t(
2441 static_cast<sdbusplus::bus_t&>(*conn),
Zev Weissa8f116a2021-09-01 21:08:30 -05002442 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2443 "PropertiesChanged',arg0='" +
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302444 cfg.interface + "'",
Zev Weissa8f116a2021-09-01 21:08:30 -05002445 std::move(pulseEventMatcherCallback));
2446}
2447
Priyatharshan P70120512020-09-16 18:47:20 +05302448int getProperty(ConfigData& configData)
2449{
2450 auto method = conn->new_method_call(
2451 configData.dbusName.c_str(), configData.path.c_str(),
2452 "org.freedesktop.DBus.Properties", "Get");
2453 method.append(configData.interface.c_str(), configData.lineName.c_str());
2454
2455 auto reply = conn->call(method);
2456 if (reply.is_method_error())
2457 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002458 lg2::error(
2459 "Error reading {PROPERTY} D-Bus property on interface {INTERFACE} and path {PATH}",
2460 "PROPERTY", configData.lineName, "INTERFACE", configData.interface,
2461 "PATH", configData.path);
Priyatharshan P70120512020-09-16 18:47:20 +05302462 return -1;
2463 }
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302464 std::variant<bool> resp;
Priyatharshan P70120512020-09-16 18:47:20 +05302465 reply.read(resp);
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302466 auto respValue = std::get_if<bool>(&resp);
Priyatharshan P70120512020-09-16 18:47:20 +05302467 if (!respValue)
2468 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002469 lg2::error("Error: {PROPERTY} D-Bus property is not the expected type",
2470 "PROPERTY", configData.lineName);
Priyatharshan P70120512020-09-16 18:47:20 +05302471 return -1;
2472 }
2473 return (*respValue);
2474}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002475} // namespace power_control
2476
2477int main(int argc, char* argv[])
2478{
Lei YU92caa4c2021-02-23 16:59:25 +08002479 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05302480
2481 if (argc > 1)
2482 {
2483 node = argv[1];
2484 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002485 lg2::info("Start Chassis power control service for host : {NODE}", "NODE",
2486 node);
Priyatharshan P70120512020-09-16 18:47:20 +05302487
Lei YU92caa4c2021-02-23 16:59:25 +08002488 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002489
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302490 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08002491 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302492 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002493 lg2::error("Host{NODE}: Error in Parsing...", "NODE", node);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302494 }
Naveen Mosesec972d82021-07-16 21:19:23 +05302495 /* Currently for single host based systems additional busname is added
2496 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
2497 Going forward for single hosts the old bus name without zero numbering
2498 will be removed when all other applications adapted to the
2499 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
2500
2501 if (node == "0")
2502 {
2503 // Request all the dbus names
2504 conn->request_name(hostDbusName.c_str());
2505 conn->request_name(chassisDbusName.c_str());
2506 conn->request_name(osDbusName.c_str());
2507 conn->request_name(buttonDbusName.c_str());
2508 conn->request_name(nmiDbusName.c_str());
2509 conn->request_name(rstCauseDbusName.c_str());
2510 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302511
Zev Weissc4005bd2021-09-01 22:30:23 -05002512 hostDbusName += node;
2513 chassisDbusName += node;
2514 osDbusName += node;
2515 buttonDbusName += node;
2516 nmiDbusName += node;
2517 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002518
Priyatharshan P70120512020-09-16 18:47:20 +05302519 // Request all the dbus names
2520 conn->request_name(hostDbusName.c_str());
2521 conn->request_name(chassisDbusName.c_str());
2522 conn->request_name(osDbusName.c_str());
2523 conn->request_name(buttonDbusName.c_str());
2524 conn->request_name(nmiDbusName.c_str());
2525 conn->request_name(rstCauseDbusName.c_str());
2526
2527 if (sioPwrGoodConfig.lineName.empty() ||
2528 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05302529 {
Lei YU92caa4c2021-02-23 16:59:25 +08002530 sioEnabled = false;
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002531 lg2::info("SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05302532 }
2533
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002534 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302535 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002536 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002537 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302538 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302539 {
2540 return -1;
2541 }
2542 }
Priyatharshan P70120512020-09-16 18:47:20 +05302543 else if (powerOkConfig.type == ConfigType::DBUS)
2544 {
2545
Patrick Williams439b9c32022-07-22 19:26:53 -05002546 static sdbusplus::bus::match_t powerOkEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002547 power_control::dbusGPIOMatcher(powerOkConfig, psPowerOKHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302548 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302549 else
2550 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002551 lg2::error("PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002552 return -1;
2553 }
2554
Lei YU92caa4c2021-02-23 16:59:25 +08002555 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002556 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05302557 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302558 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302559 {
Priyatharshan P70120512020-09-16 18:47:20 +05302560 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002561 sioPowerGoodHandler, sioPowerGoodLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302562 sioPowerGoodEvent))
2563 {
2564 return -1;
2565 }
2566 }
2567 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
2568 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002569 static sdbusplus::bus::match_t sioPwrGoodEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002570 power_control::dbusGPIOMatcher(sioPwrGoodConfig,
2571 sioPowerGoodHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302572 }
2573 else
2574 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002575 lg2::error(
Priyatharshan P70120512020-09-16 18:47:20 +05302576 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302577 return -1;
2578 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002579
Priyatharshan P19c47a32020-08-12 18:16:43 +05302580 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302581 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302582 {
Priyatharshan P70120512020-09-16 18:47:20 +05302583 if (!requestGPIOEvents(sioOnControlConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002584 sioOnControlHandler, sioOnControlLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302585 sioOnControlEvent))
2586 {
2587 return -1;
2588 }
2589 }
2590 else if (sioOnControlConfig.type == ConfigType::DBUS)
2591 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002592 static sdbusplus::bus::match_t sioOnControlEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002593 power_control::dbusGPIOMatcher(sioOnControlConfig,
2594 sioOnControlHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302595 }
2596 else
2597 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002598 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002599 "sioOnControl name should be configured from jsonconfig file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302600 return -1;
2601 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002602
Priyatharshan P19c47a32020-08-12 18:16:43 +05302603 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302604 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302605 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002606 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
Priyatharshan P70120512020-09-16 18:47:20 +05302607 sioS5Line, sioS5Event))
2608 {
2609 return -1;
2610 }
2611 }
2612 else if (sioS5Config.type == ConfigType::DBUS)
2613 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002614 static sdbusplus::bus::match_t sioS5EventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002615 power_control::dbusGPIOMatcher(sioS5Config, sioS5Handler);
Priyatharshan P70120512020-09-16 18:47:20 +05302616 }
2617 else
2618 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002619 lg2::error("sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302620 return -1;
2621 }
2622 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002623
2624 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302625 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002626 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002627 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
2628 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302629 {
2630 return -1;
2631 }
2632 }
Priyatharshan P70120512020-09-16 18:47:20 +05302633 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302634 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002635 static sdbusplus::bus::match_t powerButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002636 power_control::dbusGPIOMatcher(powerButtonConfig,
2637 powerButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002638 }
2639
2640 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302641 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002642 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002643 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
2644 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302645 {
2646 return -1;
2647 }
2648 }
Priyatharshan P70120512020-09-16 18:47:20 +05302649 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302650 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002651 static sdbusplus::bus::match_t resetButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002652 power_control::dbusGPIOMatcher(resetButtonConfig,
2653 resetButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002654 }
2655
2656 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302657 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302658 {
Priyatharshan P70120512020-09-16 18:47:20 +05302659 if (!nmiButtonConfig.lineName.empty())
2660 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002661 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302662 nmiButtonLine, nmiButtonEvent);
2663 }
2664 }
2665 else if (nmiButtonConfig.type == ConfigType::DBUS)
2666 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002667 static sdbusplus::bus::match_t nmiButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002668 power_control::dbusGPIOMatcher(nmiButtonConfig, nmiButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302669 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002670
2671 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302672 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302673 {
Priyatharshan P70120512020-09-16 18:47:20 +05302674 if (!idButtonConfig.lineName.empty())
2675 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002676 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302677 idButtonLine, idButtonEvent);
2678 }
2679 }
2680 else if (idButtonConfig.type == ConfigType::DBUS)
2681 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002682 static sdbusplus::bus::match_t idButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002683 power_control::dbusGPIOMatcher(idButtonConfig, idButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302684 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002685
Jason M. Billsfb957332021-01-28 13:18:46 -08002686#ifdef USE_PLT_RST
Patrick Williams439b9c32022-07-22 19:26:53 -05002687 sdbusplus::bus::match_t pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08002688 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08002689 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2690 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08002691 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08002692#endif
2693
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002694 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302695 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002696 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002697 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
2698 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302699 {
2700 return -1;
2701 }
2702 }
Priyatharshan P70120512020-09-16 18:47:20 +05302703 else if (postCompleteConfig.type == ConfigType::DBUS)
2704 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002705 static sdbusplus::bus::match_t postCompleteEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002706 power_control::dbusGPIOMatcher(postCompleteConfig,
2707 postCompleteHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302708 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302709 else
2710 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002711 lg2::error(
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002712 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002713 return -1;
2714 }
2715
2716 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05302717 if (!nmiOutConfig.lineName.empty())
2718 {
Ping Guo8643c792022-05-18 08:32:00 +08002719 setGPIOOutput(nmiOutConfig.lineName, nmiOutConfig.polarity, nmiOutLine);
Priyatharshan P70120512020-09-16 18:47:20 +05302720 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002721
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002722 // Initialize POWER_OUT and RESET_OUT GPIO.
2723 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05302724 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002725 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002726 if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
2727 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302728 {
2729 return -1;
2730 }
2731 }
2732 else
2733 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002734 lg2::error("powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002735 return -1;
2736 }
2737
Priyatharshan P70120512020-09-16 18:47:20 +05302738 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002739 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002740 if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
2741 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302742 {
2743 return -1;
2744 }
2745 }
2746 else
2747 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002748 lg2::error("ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002749 return -1;
2750 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002751 // Release line
2752 line.reset();
2753
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002754 // Initialize the power state
Lei YU92caa4c2021-02-23 16:59:25 +08002755 powerState = PowerState::off;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002756 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05302757
2758 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002759 {
Jean-Marie Verdun61b4a5b2021-09-19 08:53:28 -04002760 if (psPowerOKLine.get_value() > 0 ||
Lei YUa37c2472021-09-26 15:57:12 +08002761 (sioEnabled &&
2762 (sioPowerGoodLine.get_value() == sioPwrGoodConfig.polarity)))
Priyatharshan P70120512020-09-16 18:47:20 +05302763 {
2764 powerState = PowerState::on;
2765 }
2766 }
2767 else
2768 {
2769 if (getProperty(powerOkConfig))
2770 {
2771 powerState = PowerState::on;
2772 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002773 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002774 // Check if we need to start the Power Restore policy
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03002775 if (powerState != PowerState::on)
2776 {
2777 powerRestore.run();
2778 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002779
Lei YU92caa4c2021-02-23 16:59:25 +08002780 if (nmiOutLine)
2781 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002782
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002783 lg2::info("Initializing power state.");
Lei YU92caa4c2021-02-23 16:59:25 +08002784 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002785
2786 // Power Control Service
2787 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002788 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002789
2790 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05302791 hostIface =
2792 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
2793 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002794 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08002795 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002796 "RequestedHostTransition",
2797 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2798 [](const std::string& requested, std::string& resp) {
2799 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2800 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002801 // if power button is masked, ignore this
2802 if (!powerButtonMask)
2803 {
2804 sendPowerControlEvent(Event::gracefulPowerOffRequest);
2805 addRestartCause(RestartCause::command);
2806 }
2807 else
2808 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002809 lg2::info("Power Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002810 throw std::invalid_argument("Transition Request Masked");
2811 return 0;
2812 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002813 }
2814 else if (requested ==
2815 "xyz.openbmc_project.State.Host.Transition.On")
2816 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002817 // if power button is masked, ignore this
2818 if (!powerButtonMask)
2819 {
2820 sendPowerControlEvent(Event::powerOnRequest);
2821 addRestartCause(RestartCause::command);
2822 }
2823 else
2824 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002825 lg2::info("Power Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002826 throw std::invalid_argument("Transition Request Masked");
2827 return 0;
2828 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002829 }
2830 else if (requested ==
2831 "xyz.openbmc_project.State.Host.Transition.Reboot")
2832 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002833 // if power button is masked, ignore this
2834 if (!powerButtonMask)
2835 {
2836 sendPowerControlEvent(Event::powerCycleRequest);
2837 addRestartCause(RestartCause::command);
2838 }
2839 else
2840 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002841 lg2::info("Power Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002842 throw std::invalid_argument("Transition Request Masked");
2843 return 0;
2844 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002845 }
Jason M. Bills418ce112021-09-08 15:15:05 -07002846 else if (
2847 requested ==
2848 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot")
Jason M. Billse7520ba2020-01-31 11:19:03 -08002849 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002850 // if reset button is masked, ignore this
2851 if (!resetButtonMask)
2852 {
2853 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
2854 addRestartCause(RestartCause::command);
2855 }
2856 else
2857 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002858 lg2::info("Reset Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002859 throw std::invalid_argument("Transition Request Masked");
2860 return 0;
2861 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002862 }
Jason M. Bills418ce112021-09-08 15:15:05 -07002863 else if (
2864 requested ==
2865 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot")
Jason M. Billse7520ba2020-01-31 11:19:03 -08002866 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002867 // if reset button is masked, ignore this
2868 if (!resetButtonMask)
2869 {
2870 sendPowerControlEvent(Event::resetRequest);
2871 addRestartCause(RestartCause::command);
2872 }
2873 else
2874 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002875 lg2::info("Reset Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002876 throw std::invalid_argument("Transition Request Masked");
2877 return 0;
2878 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002879 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002880 else
2881 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002882 lg2::error("Unrecognized host state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002883 throw std::invalid_argument("Unrecognized Transition Request");
2884 return 0;
2885 }
2886 resp = requested;
2887 return 1;
2888 });
Lei YU92caa4c2021-02-23 16:59:25 +08002889 hostIface->register_property("CurrentHostState",
2890 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002891
Lei YU92caa4c2021-02-23 16:59:25 +08002892 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002893
2894 // Chassis Control Service
2895 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002896 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002897
2898 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002899 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05302900 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002901 "xyz.openbmc_project.State.Chassis");
2902
Lei YU92caa4c2021-02-23 16:59:25 +08002903 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002904 "RequestedPowerTransition",
2905 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
2906 [](const std::string& requested, std::string& resp) {
2907 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
2908 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002909 // if power button is masked, ignore this
2910 if (!powerButtonMask)
2911 {
2912 sendPowerControlEvent(Event::powerOffRequest);
2913 addRestartCause(RestartCause::command);
2914 }
2915 else
2916 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002917 lg2::info("Power Button Masked.");
Vernon Mauery2a269432021-07-14 10:00:21 -07002918 throw std::invalid_argument("Transition Request Masked");
2919 return 0;
2920 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002921 }
2922 else if (requested ==
2923 "xyz.openbmc_project.State.Chassis.Transition.On")
2924 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002925 // if power button is masked, ignore this
2926 if (!powerButtonMask)
2927 {
2928 sendPowerControlEvent(Event::powerOnRequest);
2929 addRestartCause(RestartCause::command);
2930 }
2931 else
2932 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002933 lg2::info("Power Button Masked.");
Vernon Mauery2a269432021-07-14 10:00:21 -07002934 throw std::invalid_argument("Transition Request Masked");
2935 return 0;
2936 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002937 }
2938 else if (requested ==
2939 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2940 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002941 // if power button is masked, ignore this
2942 if (!powerButtonMask)
2943 {
2944 sendPowerControlEvent(Event::powerCycleRequest);
2945 addRestartCause(RestartCause::command);
2946 }
2947 else
2948 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002949 lg2::info("Power Button Masked.");
Vernon Mauery2a269432021-07-14 10:00:21 -07002950 throw std::invalid_argument("Transition Request Masked");
2951 return 0;
2952 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002953 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002954 else
2955 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002956 lg2::error("Unrecognized chassis state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002957 throw std::invalid_argument("Unrecognized Transition Request");
2958 return 0;
2959 }
2960 resp = requested;
2961 return 1;
2962 });
Lei YU92caa4c2021-02-23 16:59:25 +08002963 chassisIface->register_property("CurrentPowerState",
2964 std::string(getChassisState(powerState)));
2965 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002966
Lei YU92caa4c2021-02-23 16:59:25 +08002967 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002968
Vijay Khemka04175c22020-10-09 14:28:11 -07002969#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002970 // Chassis System Service
2971 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002972 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002973
2974 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002975 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002976 "/xyz/openbmc_project/state/chassis_system0",
2977 "xyz.openbmc_project.State.Chassis");
2978
Lei YU92caa4c2021-02-23 16:59:25 +08002979 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002980 "RequestedPowerTransition",
2981 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
2982 [](const std::string& requested, std::string& resp) {
2983 if (requested ==
2984 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2985 {
Lei YU92caa4c2021-02-23 16:59:25 +08002986 systemReset();
2987 addRestartCause(RestartCause::command);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002988 }
2989 else
2990 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002991 lg2::error(
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002992 "Unrecognized chassis system state transition request.");
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002993 throw std::invalid_argument("Unrecognized Transition Request");
2994 return 0;
2995 }
2996 resp = requested;
2997 return 1;
2998 });
Lei YU92caa4c2021-02-23 16:59:25 +08002999 chassisSysIface->register_property(
3000 "CurrentPowerState", std::string(getChassisState(powerState)));
3001 chassisSysIface->register_property("LastStateChangeTime",
3002 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003003
Lei YU92caa4c2021-02-23 16:59:25 +08003004 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003005
Naveen Moses117c34e2021-05-26 20:10:51 +05303006 if (!slotPowerConfig.lineName.empty())
3007 {
3008 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3009 {
3010 return -1;
3011 }
3012
3013 slotPowerState = SlotPowerState::off;
3014 if (slotPowerLine.get_value() > 0)
3015 {
3016 slotPowerState = SlotPowerState::on;
3017 }
3018
3019 chassisSlotIface = chassisSysServer.add_interface(
3020 "/xyz/openbmc_project/state/chassis_system" + node,
3021 "xyz.openbmc_project.State.Chassis");
3022 chassisSlotIface->register_property(
3023 "RequestedPowerTransition",
3024 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3025 [](const std::string& requested, std::string& resp) {
3026 if (requested ==
3027 "xyz.openbmc_project.State.Chassis.Transition.On")
3028 {
3029 slotPowerOn();
3030 }
3031 else if (requested ==
3032 "xyz.openbmc_project.State.Chassis.Transition.Off")
3033 {
3034 slotPowerOff();
3035 }
Jason M. Bills418ce112021-09-08 15:15:05 -07003036 else if (
3037 requested ==
3038 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
Naveen Moses117c34e2021-05-26 20:10:51 +05303039 {
3040 slotPowerCycle();
3041 }
3042 else
3043 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003044 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07003045 "Unrecognized chassis system state transition request.\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05303046 throw std::invalid_argument(
3047 "Unrecognized Transition Request");
3048 return 0;
3049 }
3050 resp = requested;
3051 return 1;
3052 });
3053 chassisSlotIface->register_property(
3054 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3055 chassisSlotIface->register_property("LastStateChangeTime",
3056 getCurrentTimeMs());
3057 chassisSlotIface->initialize();
3058 }
3059#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003060 // Buttons Service
3061 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003062 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003063
Priyatharshan P70120512020-09-16 18:47:20 +05303064 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003065 {
Priyatharshan P70120512020-09-16 18:47:20 +05303066 // Power Button Interface
3067 power_control::powerButtonIface = buttonsServer.add_interface(
3068 "/xyz/openbmc_project/chassis/buttons/power",
3069 "xyz.openbmc_project.Chassis.Buttons");
3070
3071 powerButtonIface->register_property(
3072 "ButtonMasked", false, [](const bool requested, bool& current) {
3073 if (requested)
3074 {
3075 if (powerButtonMask)
3076 {
3077 return 1;
3078 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003079 if (!setGPIOOutput(powerOutConfig.lineName,
3080 !powerOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303081 powerButtonMask))
3082 {
3083 throw std::runtime_error("Failed to request GPIO");
3084 return 0;
3085 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003086 lg2::info("Power Button Masked.");
Priyatharshan P70120512020-09-16 18:47:20 +05303087 }
3088 else
3089 {
3090 if (!powerButtonMask)
3091 {
3092 return 1;
3093 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003094 lg2::info("Power Button Un-masked");
Priyatharshan P70120512020-09-16 18:47:20 +05303095 powerButtonMask.reset();
3096 }
3097 // Update the mask setting
3098 current = requested;
3099 return 1;
3100 });
3101
3102 // Check power button state
3103 bool powerButtonPressed;
3104 if (powerButtonConfig.type == ConfigType::GPIO)
3105 {
3106 powerButtonPressed = powerButtonLine.get_value() == 0;
3107 }
3108 else
3109 {
3110 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3111 }
3112
3113 powerButtonIface->register_property("ButtonPressed",
3114 powerButtonPressed);
3115
3116 powerButtonIface->initialize();
3117 }
3118
3119 if (!resetButtonConfig.lineName.empty())
3120 {
3121 // Reset Button Interface
3122
Lei YU92caa4c2021-02-23 16:59:25 +08003123 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003124 "/xyz/openbmc_project/chassis/buttons/reset",
3125 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003126
Lei YU92caa4c2021-02-23 16:59:25 +08003127 resetButtonIface->register_property(
John Wang6c090072020-09-30 13:32:16 +08003128 "ButtonMasked", false, [](const bool requested, bool& current) {
3129 if (requested)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003130 {
Lei YU92caa4c2021-02-23 16:59:25 +08003131 if (resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003132 {
3133 return 1;
3134 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003135 if (!setGPIOOutput(resetOutConfig.lineName,
3136 !resetOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303137 resetButtonMask))
John Wang6c090072020-09-30 13:32:16 +08003138 {
3139 throw std::runtime_error("Failed to request GPIO");
3140 return 0;
3141 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003142 lg2::info("Reset Button Masked.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003143 }
John Wang6c090072020-09-30 13:32:16 +08003144 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003145 {
Lei YU92caa4c2021-02-23 16:59:25 +08003146 if (!resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003147 {
3148 return 1;
3149 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003150 lg2::info("Reset Button Un-masked");
Lei YU92caa4c2021-02-23 16:59:25 +08003151 resetButtonMask.reset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003152 }
John Wang6c090072020-09-30 13:32:16 +08003153 // Update the mask setting
3154 current = requested;
3155 return 1;
3156 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003157
John Wang6c090072020-09-30 13:32:16 +08003158 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303159 bool resetButtonPressed;
3160 if (resetButtonConfig.type == ConfigType::GPIO)
3161 {
3162 resetButtonPressed = resetButtonLine.get_value() == 0;
3163 }
3164 else
3165 {
3166 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3167 }
3168
Lei YU92caa4c2021-02-23 16:59:25 +08003169 resetButtonIface->register_property("ButtonPressed",
3170 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003171
Lei YU92caa4c2021-02-23 16:59:25 +08003172 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003173 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003174
Lei YU92caa4c2021-02-23 16:59:25 +08003175 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003176 {
3177 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003178 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003179 "/xyz/openbmc_project/chassis/buttons/nmi",
3180 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003181
Lei YU92caa4c2021-02-23 16:59:25 +08003182 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003183 "ButtonMasked", false, [](const bool requested, bool& current) {
Lei YU92caa4c2021-02-23 16:59:25 +08003184 if (nmiButtonMasked == requested)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003185 {
3186 // NMI button mask is already set as requested, so no change
3187 return 1;
3188 }
3189 if (requested)
3190 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003191 lg2::info("NMI Button Masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003192 nmiButtonMasked = true;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003193 }
3194 else
3195 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003196 lg2::info("NMI Button Un-masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003197 nmiButtonMasked = false;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003198 }
3199 // Update the mask setting
Lei YU92caa4c2021-02-23 16:59:25 +08003200 current = nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003201 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003202 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003203
Vijay Khemka33a532d2019-11-14 16:50:35 -08003204 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303205 bool nmiButtonPressed;
3206 if (nmiButtonConfig.type == ConfigType::GPIO)
3207 {
3208 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3209 }
3210 else
3211 {
3212 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3213 }
3214
Lei YU92caa4c2021-02-23 16:59:25 +08003215 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003216
Lei YU92caa4c2021-02-23 16:59:25 +08003217 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003218 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003219
Lei YU92caa4c2021-02-23 16:59:25 +08003220 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003221 {
3222 // NMI out Service
3223 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003224 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003225
Vijay Khemka33a532d2019-11-14 16:50:35 -08003226 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303227 nmiOutIface = nmiOutServer.add_interface(
3228 "/xyz/openbmc_project/control/host" + node + "/nmi",
3229 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003230 nmiOutIface->register_method("NMI", nmiReset);
3231 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003232 }
Chen Yugang174ec662019-08-19 19:58:49 +08003233
Lei YU92caa4c2021-02-23 16:59:25 +08003234 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003235 {
3236 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003237 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003238 "/xyz/openbmc_project/chassis/buttons/id",
3239 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003240
Vijay Khemka33a532d2019-11-14 16:50:35 -08003241 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303242 bool idButtonPressed;
3243 if (idButtonConfig.type == ConfigType::GPIO)
3244 {
3245 idButtonPressed = idButtonLine.get_value() == 0;
3246 }
3247 else
3248 {
3249 idButtonPressed = getProperty(idButtonConfig) == 0;
3250 }
3251
Lei YU92caa4c2021-02-23 16:59:25 +08003252 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003253
Lei YU92caa4c2021-02-23 16:59:25 +08003254 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003255 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003256
3257 // OS State Service
3258 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003259 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003260
3261 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003262 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003263 "/xyz/openbmc_project/state/os",
3264 "xyz.openbmc_project.State.OperatingSystem.Status");
3265
3266 // Get the initial OS state based on POST complete
3267 // 0: Asserted, OS state is "Standby" (ready to boot)
3268 // 1: De-Asserted, OS state is "Inactive"
Tim Lee86239182021-12-23 11:46:01 +08003269 OperatingSystemStateStage osState;
Priyatharshan P70120512020-09-16 18:47:20 +05303270 if (postCompleteConfig.type == ConfigType::GPIO)
3271 {
Tim Lee86239182021-12-23 11:46:01 +08003272 osState = postCompleteLine.get_value() > 0
3273 ? OperatingSystemStateStage::Inactive
3274 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303275 }
3276 else
3277 {
Tim Lee86239182021-12-23 11:46:01 +08003278 osState = getProperty(postCompleteConfig) > 0
3279 ? OperatingSystemStateStage::Inactive
3280 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303281 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003282
Tim Lee86239182021-12-23 11:46:01 +08003283 osIface->register_property(
3284 "OperatingSystemState",
3285 std::string(getOperatingSystemStateStage(osState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003286
Lei YU92caa4c2021-02-23 16:59:25 +08003287 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003288
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003289 // Restart Cause Service
3290 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003291 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003292
3293 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003294 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303295 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003296 "xyz.openbmc_project.Control.Host.RestartCause");
3297
Lei YU92caa4c2021-02-23 16:59:25 +08003298 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003299 "RestartCause",
3300 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3301
Lei YU92caa4c2021-02-23 16:59:25 +08003302 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003303 "RequestedRestartCause",
3304 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3305 [](const std::string& requested, std::string& resp) {
3306 if (requested ==
3307 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3308 {
Lei YU92caa4c2021-02-23 16:59:25 +08003309 addRestartCause(RestartCause::watchdog);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003310 }
3311 else
3312 {
3313 throw std::invalid_argument(
3314 "Unrecognized RestartCause Request");
3315 return 0;
3316 }
3317
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003318 lg2::info("RestartCause requested: {RESTART_CAUSE}",
3319 "RESTART_CAUSE", requested);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003320 resp = requested;
3321 return 1;
3322 });
3323
Lei YU92caa4c2021-02-23 16:59:25 +08003324 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003325
Lei YU92caa4c2021-02-23 16:59:25 +08003326 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003327
Lei YU92caa4c2021-02-23 16:59:25 +08003328 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003329
3330 return 0;
3331}