blob: 514806a791f807267e351463e9cdbb98cb5af7ad [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";
861static constexpr char const* powerRestorePolicyObject =
862 "/xyz/openbmc_project/control/host0/power_restore_policy";
863static constexpr char const* powerRestorePolicyIface =
864 "xyz.openbmc_project.Control.Power.RestorePolicy";
865#ifdef USE_ACBOOT
866static constexpr char const* powerACBootObject =
867 "/xyz/openbmc_project/control/host0/ac_boot";
868static constexpr char const* powerACBootIface =
869 "xyz.openbmc_project.Common.ACBoot";
870#endif // USE_ACBOOT
871
872namespace match_rules = sdbusplus::bus::match::rules;
873
874static int powerRestoreConfigHandler(sd_bus_message* m, void* context,
875 sd_bus_error*)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700876{
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300877 if (context == nullptr || m == nullptr)
878 {
879 throw std::runtime_error("Invalid match");
880 }
Patrick Williams439b9c32022-07-22 19:26:53 -0500881 sdbusplus::message_t message(m);
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300882 PowerRestoreController* powerRestore =
883 static_cast<PowerRestoreController*>(context);
884
885 if (std::string(message.get_member()) == "InterfacesAdded")
886 {
887 sdbusplus::message::object_path path;
888 boost::container::flat_map<std::string, dbusPropertiesList> data;
889
890 message.read(path, data);
891
892 for (auto& [iface, properties] : data)
893 {
894 if ((iface == powerRestorePolicyIface)
895#ifdef USE_ACBOOT
896 || (iface == powerACBootIface)
897#endif // USE_ACBOOT
898 )
899 {
900 powerRestore->setProperties(properties);
901 }
902 }
903 }
904 else if (std::string(message.get_member()) == "PropertiesChanged")
905 {
906 std::string interfaceName;
907 dbusPropertiesList propertiesChanged;
908
909 message.read(interfaceName, propertiesChanged);
910
911 powerRestore->setProperties(propertiesChanged);
912 }
913 return 1;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700914}
915
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300916void PowerRestoreController::run()
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700917{
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{
2073 static constexpr const uint8_t value = 1;
2074 const static constexpr int nmiOutPulseTimeMs = 200;
2075
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002076 lg2::info("NMI out action");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002077 nmiOutLine.set_value(value);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002078 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME",
2079 nmiOutConfig.lineName, "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002080 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2081 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2082 // restore the NMI_OUT GPIO line back to the opposite value
2083 nmiOutLine.set_value(!value);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002084 lg2::info("{GPIO_NAME} released", "GPIO_NAME", nmiOutConfig.lineName);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002085 if (ec)
2086 {
2087 // operation_aborted is expected if timer is canceled before
2088 // completion.
2089 if (ec != boost::asio::error::operation_aborted)
2090 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002091 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
2092 "GPIO_NAME", nmiOutConfig.lineName, "ERROR_MSG",
2093 ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002094 }
2095 }
2096 });
2097 // log to redfish
2098 nmiDiagIntLog();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002099 lg2::info("NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002100 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002101 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002102}
2103
2104static void nmiSourcePropertyMonitor(void)
2105{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002106 lg2::info("NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002107
Patrick Williams439b9c32022-07-22 19:26:53 -05002108 static std::unique_ptr<sdbusplus::bus::match_t> nmiSourceMatch =
2109 std::make_unique<sdbusplus::bus::match_t>(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002110 *conn,
2111 "type='signal',interface='org.freedesktop.DBus.Properties',"
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002112 "member='PropertiesChanged',"
2113 "arg0namespace='xyz.openbmc_project.Chassis.Control.NMISource'",
Patrick Williams439b9c32022-07-22 19:26:53 -05002114 [](sdbusplus::message_t& msg) {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002115 std::string interfaceName;
2116 boost::container::flat_map<std::string,
2117 std::variant<bool, std::string>>
2118 propertiesChanged;
2119 std::string state;
2120 bool value = true;
2121 try
2122 {
2123 msg.read(interfaceName, propertiesChanged);
2124 if (propertiesChanged.begin()->first == "Enabled")
2125 {
2126 value =
2127 std::get<bool>(propertiesChanged.begin()->second);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002128 lg2::info(
2129 "NMI Enabled propertiesChanged value: {VALUE}",
2130 "VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002131 nmiEnabled = value;
2132 if (nmiEnabled)
2133 {
2134 nmiReset();
2135 }
2136 }
2137 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002138 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002139 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002140 lg2::error("Unable to read NMI source: {ERROR}", "ERROR",
2141 e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002142 return;
2143 }
2144 });
2145}
2146
2147static void setNmiSource()
2148{
2149 conn->async_method_call(
2150 [](boost::system::error_code ec) {
2151 if (ec)
2152 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002153 lg2::error("failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002154 }
2155 },
Chen Yugang303bd582019-11-01 08:45:06 +08002156 "xyz.openbmc_project.Settings",
2157 "/xyz/openbmc_project/Chassis/Control/NMISource",
2158 "org.freedesktop.DBus.Properties", "Set",
2159 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
Jason M. Bills418ce112021-09-08 15:15:05 -07002160 std::variant<std::string>{
2161 "xyz.openbmc_project.Chassis.Control.NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002162 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002163 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002164}
2165
Zev Weiss584aa132021-09-02 19:21:52 -05002166static void nmiButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002167{
Zev Weiss584aa132021-09-02 19:21:52 -05002168 nmiButtonIface->set_property("ButtonPressed", !state);
2169 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002170 {
2171 nmiButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002172 if (nmiButtonMasked)
2173 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002174 lg2::info("NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002175 }
2176 else
2177 {
2178 setNmiSource();
2179 }
2180 }
Zev Weiss584aa132021-09-02 19:21:52 -05002181}
2182
Zev Weiss584aa132021-09-02 19:21:52 -05002183static void idButtonHandler(bool state)
2184{
2185 idButtonIface->set_property("ButtonPressed", !state);
2186}
2187
Jason M. Billsfb957332021-01-28 13:18:46 -08002188static void pltRstHandler(bool pltRst)
2189{
2190 if (pltRst)
2191 {
2192 sendPowerControlEvent(Event::pltRstDeAssert);
2193 }
2194 else
2195 {
2196 sendPowerControlEvent(Event::pltRstAssert);
2197 }
2198}
2199
Patrick Williams439b9c32022-07-22 19:26:53 -05002200[[maybe_unused]] static void hostMiscHandler(sdbusplus::message_t& msg)
Jason M. Billsfb957332021-01-28 13:18:46 -08002201{
2202 std::string interfaceName;
2203 boost::container::flat_map<std::string, std::variant<bool>>
2204 propertiesChanged;
Jason M. Billsfb957332021-01-28 13:18:46 -08002205 try
2206 {
2207 msg.read(interfaceName, propertiesChanged);
2208 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002209 catch (const std::exception& e)
Jason M. Billsfb957332021-01-28 13:18:46 -08002210 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002211 lg2::error("Unable to read Host Misc status: {ERROR}", "ERROR", e);
Jason M. Billsfb957332021-01-28 13:18:46 -08002212 return;
2213 }
2214 if (propertiesChanged.empty())
2215 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002216 lg2::error("ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002217 return;
2218 }
2219
2220 for (auto& [property, value] : propertiesChanged)
2221 {
2222 if (property == "ESpiPlatformReset")
2223 {
2224 bool* pltRst = std::get_if<bool>(&value);
2225 if (pltRst == nullptr)
2226 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002227 lg2::error("{PROPERTY} property invalid", "PROPERTY", property);
Jason M. Billsfb957332021-01-28 13:18:46 -08002228 return;
2229 }
2230 pltRstHandler(*pltRst);
2231 }
2232 }
2233}
2234
Zev Weiss584aa132021-09-02 19:21:52 -05002235static void postCompleteHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002236{
Zev Weiss584aa132021-09-02 19:21:52 -05002237 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002238 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002239 sendPowerControlEvent(Event::postCompleteAssert);
Tim Lee86239182021-12-23 11:46:01 +08002240 setOperatingSystemState(OperatingSystemStateStage::Standby);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002241 }
2242 else
2243 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002244 sendPowerControlEvent(Event::postCompleteDeAssert);
Tim Lee86239182021-12-23 11:46:01 +08002245 setOperatingSystemState(OperatingSystemStateStage::Inactive);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002246 }
Zev Weiss584aa132021-09-02 19:21:52 -05002247}
2248
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302249static int loadConfigValues()
2250{
2251 const std::string configFilePath =
2252 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2253 ".json";
2254 std::ifstream configFile(configFilePath.c_str());
2255 if (!configFile.is_open())
2256 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002257 lg2::error("loadConfigValues: Cannot open config path \'{PATH}\'",
2258 "PATH", configFilePath);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302259 return -1;
2260 }
Zev Weiss1aa08b22021-09-15 17:06:20 -05002261 auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302262
Priyatharshan P70120512020-09-16 18:47:20 +05302263 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302264 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002265 lg2::error("Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302266 return -1;
2267 }
Priyatharshan P70120512020-09-16 18:47:20 +05302268 auto gpios = jsonData["gpio_configs"];
2269 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302270
Priyatharshan P70120512020-09-16 18:47:20 +05302271 ConfigData* tempGpioData;
2272
2273 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302274 {
Priyatharshan P70120512020-09-16 18:47:20 +05302275 if (!gpioConfig.contains("Name"))
2276 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002277 lg2::error("The 'Name' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302278 return -1;
2279 }
2280
2281 // Iterate through the powersignal map to check if the gpio json config
2282 // entry is valid
2283 std::string gpioName = gpioConfig["Name"];
2284 auto signalMapIter = powerSignalMap.find(gpioName);
2285 if (signalMapIter == powerSignalMap.end())
2286 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002287 lg2::error(
2288 "{GPIO_NAME} is not a recognized power-control signal name",
2289 "GPIO_NAME", gpioName);
Priyatharshan P70120512020-09-16 18:47:20 +05302290 return -1;
2291 }
2292
2293 // assign the power signal name to the corresponding structure reference
2294 // from map then fillup the structure with coressponding json config
2295 // value
2296 tempGpioData = signalMapIter->second;
2297 tempGpioData->name = gpioName;
2298
2299 if (!gpioConfig.contains("Type"))
2300 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002301 lg2::error("The \'Type\' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302302 return -1;
2303 }
2304
2305 std::string signalType = gpioConfig["Type"];
2306 if (signalType == "GPIO")
2307 {
2308 tempGpioData->type = ConfigType::GPIO;
2309 }
2310 else if (signalType == "DBUS")
2311 {
2312 tempGpioData->type = ConfigType::DBUS;
2313 }
2314 else
2315 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002316 lg2::error("{TYPE} is not a recognized power-control signal type",
2317 "TYPE", signalType);
Priyatharshan P70120512020-09-16 18:47:20 +05302318 return -1;
2319 }
2320
2321 if (tempGpioData->type == ConfigType::GPIO)
2322 {
2323 if (gpioConfig.contains("LineName"))
2324 {
2325 tempGpioData->lineName = gpioConfig["LineName"];
2326 }
2327 else
2328 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002329 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002330 "The \'LineName\' field must be defined for GPIO configuration");
Priyatharshan P70120512020-09-16 18:47:20 +05302331 return -1;
2332 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002333 if (gpioConfig.contains("Polarity"))
2334 {
2335 std::string polarity = gpioConfig["Polarity"];
2336 if (polarity == "ActiveLow")
2337 {
2338 tempGpioData->polarity = false;
2339 }
2340 else if (polarity == "ActiveHigh")
2341 {
2342 tempGpioData->polarity = true;
2343 }
2344 else
2345 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002346 lg2::error(
2347 "Polarity defined but not properly setup. Please only ActiveHigh or ActiveLow. Currently set to {POLARITY}",
2348 "POLARITY", polarity);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002349 return -1;
2350 }
2351 }
2352 else
2353 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002354 lg2::error("Polarity field not found for {GPIO_NAME}",
2355 "GPIO_NAME", tempGpioData->lineName);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002356 return -1;
2357 }
Priyatharshan P70120512020-09-16 18:47:20 +05302358 }
2359 else
2360 {
2361 // if dbus based gpio config is defined read and update the dbus
2362 // params corresponding to the gpio config instance
2363 for (auto& [key, dbusParamName] : dbusParams)
2364 {
Logananth Sundararaja4308042021-10-20 11:52:05 +05302365 if (!gpioConfig.contains(dbusParamName))
Priyatharshan P70120512020-09-16 18:47:20 +05302366 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002367 lg2::error(
2368 "The {DBUS_NAME} field must be defined for Dbus configuration ",
2369 "DBUS_NAME", dbusParamName);
Priyatharshan P70120512020-09-16 18:47:20 +05302370 return -1;
2371 }
2372 }
Logananth Sundararaja4308042021-10-20 11:52:05 +05302373 tempGpioData->dbusName =
2374 gpioConfig[dbusParams[DbusConfigType::name]];
2375 tempGpioData->path = gpioConfig[dbusParams[DbusConfigType::path]];
Priyatharshan P70120512020-09-16 18:47:20 +05302376 tempGpioData->interface =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302377 gpioConfig[dbusParams[DbusConfigType::interface]];
Priyatharshan P70120512020-09-16 18:47:20 +05302378 tempGpioData->lineName =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302379 gpioConfig[dbusParams[DbusConfigType::property]];
Priyatharshan P70120512020-09-16 18:47:20 +05302380 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302381 }
2382
Priyatharshan P70120512020-09-16 18:47:20 +05302383 // read and store the timer values from json config to Timer Map
2384 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302385 {
Priyatharshan P70120512020-09-16 18:47:20 +05302386 if (timers.contains(key.c_str()))
2387 {
2388 timerValue = timers[key.c_str()];
2389 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302390 }
2391
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302392 return 0;
2393}
Zev Weissa8f116a2021-09-01 21:08:30 -05002394
Patrick Williams439b9c32022-07-22 19:26:53 -05002395static bool getDbusMsgGPIOState(sdbusplus::message_t& msg,
Zev Weissa8f116a2021-09-01 21:08:30 -05002396 const std::string& lineName, bool& value)
2397{
2398 std::string thresholdInterface;
2399 std::string event;
2400 boost::container::flat_map<std::string, std::variant<bool>>
2401 propertiesChanged;
2402 try
2403 {
2404 msg.read(thresholdInterface, propertiesChanged);
2405 if (propertiesChanged.empty())
2406 {
2407 return false;
2408 }
2409
2410 event = propertiesChanged.begin()->first;
2411 if (event.empty() || event != lineName)
2412 {
2413 return false;
2414 }
2415
2416 value = std::get<bool>(propertiesChanged.begin()->second);
2417 return true;
2418 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002419 catch (const std::exception& e)
Zev Weissa8f116a2021-09-01 21:08:30 -05002420 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002421 lg2::error(
2422 "exception while reading dbus property \'{DBUS_NAME}\': {ERROR}",
2423 "DBUS_NAME", lineName, "ERROR", e);
Zev Weissa8f116a2021-09-01 21:08:30 -05002424 return false;
2425 }
2426}
2427
Patrick Williams439b9c32022-07-22 19:26:53 -05002428static sdbusplus::bus::match_t
Zev Weissa8f116a2021-09-01 21:08:30 -05002429 dbusGPIOMatcher(const ConfigData& cfg, std::function<void(bool)> onMatch)
2430{
Patrick Williams439b9c32022-07-22 19:26:53 -05002431 auto pulseEventMatcherCallback = [&cfg,
2432 onMatch](sdbusplus::message_t& msg) {
2433 bool value = false;
2434 if (!getDbusMsgGPIOState(msg, cfg.lineName, value))
2435 {
2436 return;
2437 }
2438 onMatch(value);
2439 };
Zev Weissa8f116a2021-09-01 21:08:30 -05002440
Patrick Williams439b9c32022-07-22 19:26:53 -05002441 return sdbusplus::bus::match_t(
2442 static_cast<sdbusplus::bus_t&>(*conn),
Zev Weissa8f116a2021-09-01 21:08:30 -05002443 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2444 "PropertiesChanged',arg0='" +
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302445 cfg.interface + "'",
Zev Weissa8f116a2021-09-01 21:08:30 -05002446 std::move(pulseEventMatcherCallback));
2447}
2448
Priyatharshan P70120512020-09-16 18:47:20 +05302449int getProperty(ConfigData& configData)
2450{
2451 auto method = conn->new_method_call(
2452 configData.dbusName.c_str(), configData.path.c_str(),
2453 "org.freedesktop.DBus.Properties", "Get");
2454 method.append(configData.interface.c_str(), configData.lineName.c_str());
2455
2456 auto reply = conn->call(method);
2457 if (reply.is_method_error())
2458 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002459 lg2::error(
2460 "Error reading {PROPERTY} D-Bus property on interface {INTERFACE} and path {PATH}",
2461 "PROPERTY", configData.lineName, "INTERFACE", configData.interface,
2462 "PATH", configData.path);
Priyatharshan P70120512020-09-16 18:47:20 +05302463 return -1;
2464 }
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302465 std::variant<bool> resp;
Priyatharshan P70120512020-09-16 18:47:20 +05302466 reply.read(resp);
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302467 auto respValue = std::get_if<bool>(&resp);
Priyatharshan P70120512020-09-16 18:47:20 +05302468 if (!respValue)
2469 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002470 lg2::error("Error: {PROPERTY} D-Bus property is not the expected type",
2471 "PROPERTY", configData.lineName);
Priyatharshan P70120512020-09-16 18:47:20 +05302472 return -1;
2473 }
2474 return (*respValue);
2475}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002476} // namespace power_control
2477
2478int main(int argc, char* argv[])
2479{
Lei YU92caa4c2021-02-23 16:59:25 +08002480 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05302481
2482 if (argc > 1)
2483 {
2484 node = argv[1];
2485 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002486 lg2::info("Start Chassis power control service for host : {NODE}", "NODE",
2487 node);
Priyatharshan P70120512020-09-16 18:47:20 +05302488
Lei YU92caa4c2021-02-23 16:59:25 +08002489 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002490
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302491 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08002492 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302493 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002494 lg2::error("Host{NODE}: Error in Parsing...", "NODE", node);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302495 }
Naveen Mosesec972d82021-07-16 21:19:23 +05302496 /* Currently for single host based systems additional busname is added
2497 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
2498 Going forward for single hosts the old bus name without zero numbering
2499 will be removed when all other applications adapted to the
2500 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
2501
2502 if (node == "0")
2503 {
2504 // Request all the dbus names
2505 conn->request_name(hostDbusName.c_str());
2506 conn->request_name(chassisDbusName.c_str());
2507 conn->request_name(osDbusName.c_str());
2508 conn->request_name(buttonDbusName.c_str());
2509 conn->request_name(nmiDbusName.c_str());
2510 conn->request_name(rstCauseDbusName.c_str());
2511 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302512
Zev Weissc4005bd2021-09-01 22:30:23 -05002513 hostDbusName += node;
2514 chassisDbusName += node;
2515 osDbusName += node;
2516 buttonDbusName += node;
2517 nmiDbusName += node;
2518 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002519
Priyatharshan P70120512020-09-16 18:47:20 +05302520 // Request all the dbus names
2521 conn->request_name(hostDbusName.c_str());
2522 conn->request_name(chassisDbusName.c_str());
2523 conn->request_name(osDbusName.c_str());
2524 conn->request_name(buttonDbusName.c_str());
2525 conn->request_name(nmiDbusName.c_str());
2526 conn->request_name(rstCauseDbusName.c_str());
2527
2528 if (sioPwrGoodConfig.lineName.empty() ||
2529 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05302530 {
Lei YU92caa4c2021-02-23 16:59:25 +08002531 sioEnabled = false;
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002532 lg2::info("SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05302533 }
2534
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002535 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302536 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002537 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002538 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302539 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302540 {
2541 return -1;
2542 }
2543 }
Priyatharshan P70120512020-09-16 18:47:20 +05302544 else if (powerOkConfig.type == ConfigType::DBUS)
2545 {
2546
Patrick Williams439b9c32022-07-22 19:26:53 -05002547 static sdbusplus::bus::match_t powerOkEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002548 power_control::dbusGPIOMatcher(powerOkConfig, psPowerOKHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302549 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302550 else
2551 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002552 lg2::error("PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002553 return -1;
2554 }
2555
Lei YU92caa4c2021-02-23 16:59:25 +08002556 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002557 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05302558 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302559 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302560 {
Priyatharshan P70120512020-09-16 18:47:20 +05302561 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002562 sioPowerGoodHandler, sioPowerGoodLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302563 sioPowerGoodEvent))
2564 {
2565 return -1;
2566 }
2567 }
2568 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
2569 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002570 static sdbusplus::bus::match_t sioPwrGoodEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002571 power_control::dbusGPIOMatcher(sioPwrGoodConfig,
2572 sioPowerGoodHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302573 }
2574 else
2575 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002576 lg2::error(
Priyatharshan P70120512020-09-16 18:47:20 +05302577 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302578 return -1;
2579 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002580
Priyatharshan P19c47a32020-08-12 18:16:43 +05302581 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302582 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302583 {
Priyatharshan P70120512020-09-16 18:47:20 +05302584 if (!requestGPIOEvents(sioOnControlConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002585 sioOnControlHandler, sioOnControlLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302586 sioOnControlEvent))
2587 {
2588 return -1;
2589 }
2590 }
2591 else if (sioOnControlConfig.type == ConfigType::DBUS)
2592 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002593 static sdbusplus::bus::match_t sioOnControlEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002594 power_control::dbusGPIOMatcher(sioOnControlConfig,
2595 sioOnControlHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302596 }
2597 else
2598 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002599 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002600 "sioOnControl name should be configured from jsonconfig file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302601 return -1;
2602 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002603
Priyatharshan P19c47a32020-08-12 18:16:43 +05302604 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302605 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302606 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002607 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
Priyatharshan P70120512020-09-16 18:47:20 +05302608 sioS5Line, sioS5Event))
2609 {
2610 return -1;
2611 }
2612 }
2613 else if (sioS5Config.type == ConfigType::DBUS)
2614 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002615 static sdbusplus::bus::match_t sioS5EventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002616 power_control::dbusGPIOMatcher(sioS5Config, sioS5Handler);
Priyatharshan P70120512020-09-16 18:47:20 +05302617 }
2618 else
2619 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002620 lg2::error("sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302621 return -1;
2622 }
2623 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002624
2625 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302626 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002627 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002628 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
2629 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302630 {
2631 return -1;
2632 }
2633 }
Priyatharshan P70120512020-09-16 18:47:20 +05302634 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302635 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002636 static sdbusplus::bus::match_t powerButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002637 power_control::dbusGPIOMatcher(powerButtonConfig,
2638 powerButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002639 }
2640
2641 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302642 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002643 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002644 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
2645 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302646 {
2647 return -1;
2648 }
2649 }
Priyatharshan P70120512020-09-16 18:47:20 +05302650 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302651 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002652 static sdbusplus::bus::match_t resetButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002653 power_control::dbusGPIOMatcher(resetButtonConfig,
2654 resetButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002655 }
2656
2657 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302658 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302659 {
Priyatharshan P70120512020-09-16 18:47:20 +05302660 if (!nmiButtonConfig.lineName.empty())
2661 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002662 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302663 nmiButtonLine, nmiButtonEvent);
2664 }
2665 }
2666 else if (nmiButtonConfig.type == ConfigType::DBUS)
2667 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002668 static sdbusplus::bus::match_t nmiButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002669 power_control::dbusGPIOMatcher(nmiButtonConfig, nmiButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302670 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002671
2672 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302673 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302674 {
Priyatharshan P70120512020-09-16 18:47:20 +05302675 if (!idButtonConfig.lineName.empty())
2676 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002677 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302678 idButtonLine, idButtonEvent);
2679 }
2680 }
2681 else if (idButtonConfig.type == ConfigType::DBUS)
2682 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002683 static sdbusplus::bus::match_t idButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002684 power_control::dbusGPIOMatcher(idButtonConfig, idButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302685 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002686
Jason M. Billsfb957332021-01-28 13:18:46 -08002687#ifdef USE_PLT_RST
Patrick Williams439b9c32022-07-22 19:26:53 -05002688 sdbusplus::bus::match_t pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08002689 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08002690 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2691 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08002692 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08002693#endif
2694
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002695 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302696 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002697 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002698 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
2699 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302700 {
2701 return -1;
2702 }
2703 }
Priyatharshan P70120512020-09-16 18:47:20 +05302704 else if (postCompleteConfig.type == ConfigType::DBUS)
2705 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002706 static sdbusplus::bus::match_t postCompleteEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002707 power_control::dbusGPIOMatcher(postCompleteConfig,
2708 postCompleteHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302709 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302710 else
2711 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002712 lg2::error(
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002713 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002714 return -1;
2715 }
2716
2717 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05302718 if (!nmiOutConfig.lineName.empty())
2719 {
2720 setGPIOOutput(nmiOutConfig.lineName, 0, nmiOutLine);
2721 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002722
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002723 // Initialize POWER_OUT and RESET_OUT GPIO.
2724 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05302725 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002726 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002727 if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
2728 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302729 {
2730 return -1;
2731 }
2732 }
2733 else
2734 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002735 lg2::error("powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002736 return -1;
2737 }
2738
Priyatharshan P70120512020-09-16 18:47:20 +05302739 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002740 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002741 if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
2742 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302743 {
2744 return -1;
2745 }
2746 }
2747 else
2748 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002749 lg2::error("ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002750 return -1;
2751 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002752 // Release line
2753 line.reset();
2754
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002755 // Initialize the power state
Lei YU92caa4c2021-02-23 16:59:25 +08002756 powerState = PowerState::off;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002757 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05302758
2759 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002760 {
Jean-Marie Verdun61b4a5b2021-09-19 08:53:28 -04002761 if (psPowerOKLine.get_value() > 0 ||
Lei YUa37c2472021-09-26 15:57:12 +08002762 (sioEnabled &&
2763 (sioPowerGoodLine.get_value() == sioPwrGoodConfig.polarity)))
Priyatharshan P70120512020-09-16 18:47:20 +05302764 {
2765 powerState = PowerState::on;
2766 }
2767 }
2768 else
2769 {
2770 if (getProperty(powerOkConfig))
2771 {
2772 powerState = PowerState::on;
2773 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002774 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002775 // Check if we need to start the Power Restore policy
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03002776 if (powerState != PowerState::on)
2777 {
2778 powerRestore.run();
2779 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002780
Lei YU92caa4c2021-02-23 16:59:25 +08002781 if (nmiOutLine)
2782 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002783
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002784 lg2::info("Initializing power state.");
Lei YU92caa4c2021-02-23 16:59:25 +08002785 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002786
2787 // Power Control Service
2788 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002789 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002790
2791 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05302792 hostIface =
2793 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
2794 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002795 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08002796 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002797 "RequestedHostTransition",
2798 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2799 [](const std::string& requested, std::string& resp) {
2800 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2801 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002802 // if power button is masked, ignore this
2803 if (!powerButtonMask)
2804 {
2805 sendPowerControlEvent(Event::gracefulPowerOffRequest);
2806 addRestartCause(RestartCause::command);
2807 }
2808 else
2809 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002810 lg2::info("Power Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002811 throw std::invalid_argument("Transition Request Masked");
2812 return 0;
2813 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002814 }
2815 else if (requested ==
2816 "xyz.openbmc_project.State.Host.Transition.On")
2817 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002818 // if power button is masked, ignore this
2819 if (!powerButtonMask)
2820 {
2821 sendPowerControlEvent(Event::powerOnRequest);
2822 addRestartCause(RestartCause::command);
2823 }
2824 else
2825 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002826 lg2::info("Power Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002827 throw std::invalid_argument("Transition Request Masked");
2828 return 0;
2829 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002830 }
2831 else if (requested ==
2832 "xyz.openbmc_project.State.Host.Transition.Reboot")
2833 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002834 // if power button is masked, ignore this
2835 if (!powerButtonMask)
2836 {
2837 sendPowerControlEvent(Event::powerCycleRequest);
2838 addRestartCause(RestartCause::command);
2839 }
2840 else
2841 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002842 lg2::info("Power Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002843 throw std::invalid_argument("Transition Request Masked");
2844 return 0;
2845 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002846 }
Jason M. Bills418ce112021-09-08 15:15:05 -07002847 else if (
2848 requested ==
2849 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot")
Jason M. Billse7520ba2020-01-31 11:19:03 -08002850 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002851 // if reset button is masked, ignore this
2852 if (!resetButtonMask)
2853 {
2854 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
2855 addRestartCause(RestartCause::command);
2856 }
2857 else
2858 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002859 lg2::info("Reset Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002860 throw std::invalid_argument("Transition Request Masked");
2861 return 0;
2862 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002863 }
Jason M. Bills418ce112021-09-08 15:15:05 -07002864 else if (
2865 requested ==
2866 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot")
Jason M. Billse7520ba2020-01-31 11:19:03 -08002867 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002868 // if reset button is masked, ignore this
2869 if (!resetButtonMask)
2870 {
2871 sendPowerControlEvent(Event::resetRequest);
2872 addRestartCause(RestartCause::command);
2873 }
2874 else
2875 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002876 lg2::info("Reset Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002877 throw std::invalid_argument("Transition Request Masked");
2878 return 0;
2879 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002880 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002881 else
2882 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002883 lg2::error("Unrecognized host state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002884 throw std::invalid_argument("Unrecognized Transition Request");
2885 return 0;
2886 }
2887 resp = requested;
2888 return 1;
2889 });
Lei YU92caa4c2021-02-23 16:59:25 +08002890 hostIface->register_property("CurrentHostState",
2891 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002892
Lei YU92caa4c2021-02-23 16:59:25 +08002893 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002894
2895 // Chassis Control Service
2896 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002897 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002898
2899 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002900 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05302901 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002902 "xyz.openbmc_project.State.Chassis");
2903
Lei YU92caa4c2021-02-23 16:59:25 +08002904 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002905 "RequestedPowerTransition",
2906 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
2907 [](const std::string& requested, std::string& resp) {
2908 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
2909 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002910 // if power button is masked, ignore this
2911 if (!powerButtonMask)
2912 {
2913 sendPowerControlEvent(Event::powerOffRequest);
2914 addRestartCause(RestartCause::command);
2915 }
2916 else
2917 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002918 lg2::info("Power Button Masked.");
Vernon Mauery2a269432021-07-14 10:00:21 -07002919 throw std::invalid_argument("Transition Request Masked");
2920 return 0;
2921 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002922 }
2923 else if (requested ==
2924 "xyz.openbmc_project.State.Chassis.Transition.On")
2925 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002926 // if power button is masked, ignore this
2927 if (!powerButtonMask)
2928 {
2929 sendPowerControlEvent(Event::powerOnRequest);
2930 addRestartCause(RestartCause::command);
2931 }
2932 else
2933 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002934 lg2::info("Power Button Masked.");
Vernon Mauery2a269432021-07-14 10:00:21 -07002935 throw std::invalid_argument("Transition Request Masked");
2936 return 0;
2937 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002938 }
2939 else if (requested ==
2940 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2941 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002942 // if power button is masked, ignore this
2943 if (!powerButtonMask)
2944 {
2945 sendPowerControlEvent(Event::powerCycleRequest);
2946 addRestartCause(RestartCause::command);
2947 }
2948 else
2949 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002950 lg2::info("Power Button Masked.");
Vernon Mauery2a269432021-07-14 10:00:21 -07002951 throw std::invalid_argument("Transition Request Masked");
2952 return 0;
2953 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002954 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002955 else
2956 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002957 lg2::error("Unrecognized chassis state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002958 throw std::invalid_argument("Unrecognized Transition Request");
2959 return 0;
2960 }
2961 resp = requested;
2962 return 1;
2963 });
Lei YU92caa4c2021-02-23 16:59:25 +08002964 chassisIface->register_property("CurrentPowerState",
2965 std::string(getChassisState(powerState)));
2966 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002967
Lei YU92caa4c2021-02-23 16:59:25 +08002968 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002969
Vijay Khemka04175c22020-10-09 14:28:11 -07002970#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002971 // Chassis System Service
2972 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002973 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002974
2975 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002976 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002977 "/xyz/openbmc_project/state/chassis_system0",
2978 "xyz.openbmc_project.State.Chassis");
2979
Lei YU92caa4c2021-02-23 16:59:25 +08002980 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002981 "RequestedPowerTransition",
2982 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
2983 [](const std::string& requested, std::string& resp) {
2984 if (requested ==
2985 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2986 {
Lei YU92caa4c2021-02-23 16:59:25 +08002987 systemReset();
2988 addRestartCause(RestartCause::command);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002989 }
2990 else
2991 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002992 lg2::error(
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002993 "Unrecognized chassis system state transition request.");
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002994 throw std::invalid_argument("Unrecognized Transition Request");
2995 return 0;
2996 }
2997 resp = requested;
2998 return 1;
2999 });
Lei YU92caa4c2021-02-23 16:59:25 +08003000 chassisSysIface->register_property(
3001 "CurrentPowerState", std::string(getChassisState(powerState)));
3002 chassisSysIface->register_property("LastStateChangeTime",
3003 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003004
Lei YU92caa4c2021-02-23 16:59:25 +08003005 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003006
Naveen Moses117c34e2021-05-26 20:10:51 +05303007 if (!slotPowerConfig.lineName.empty())
3008 {
3009 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3010 {
3011 return -1;
3012 }
3013
3014 slotPowerState = SlotPowerState::off;
3015 if (slotPowerLine.get_value() > 0)
3016 {
3017 slotPowerState = SlotPowerState::on;
3018 }
3019
3020 chassisSlotIface = chassisSysServer.add_interface(
3021 "/xyz/openbmc_project/state/chassis_system" + node,
3022 "xyz.openbmc_project.State.Chassis");
3023 chassisSlotIface->register_property(
3024 "RequestedPowerTransition",
3025 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3026 [](const std::string& requested, std::string& resp) {
3027 if (requested ==
3028 "xyz.openbmc_project.State.Chassis.Transition.On")
3029 {
3030 slotPowerOn();
3031 }
3032 else if (requested ==
3033 "xyz.openbmc_project.State.Chassis.Transition.Off")
3034 {
3035 slotPowerOff();
3036 }
Jason M. Bills418ce112021-09-08 15:15:05 -07003037 else if (
3038 requested ==
3039 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
Naveen Moses117c34e2021-05-26 20:10:51 +05303040 {
3041 slotPowerCycle();
3042 }
3043 else
3044 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003045 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07003046 "Unrecognized chassis system state transition request.\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05303047 throw std::invalid_argument(
3048 "Unrecognized Transition Request");
3049 return 0;
3050 }
3051 resp = requested;
3052 return 1;
3053 });
3054 chassisSlotIface->register_property(
3055 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3056 chassisSlotIface->register_property("LastStateChangeTime",
3057 getCurrentTimeMs());
3058 chassisSlotIface->initialize();
3059 }
3060#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003061 // Buttons Service
3062 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003063 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003064
Priyatharshan P70120512020-09-16 18:47:20 +05303065 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003066 {
Priyatharshan P70120512020-09-16 18:47:20 +05303067 // Power Button Interface
3068 power_control::powerButtonIface = buttonsServer.add_interface(
3069 "/xyz/openbmc_project/chassis/buttons/power",
3070 "xyz.openbmc_project.Chassis.Buttons");
3071
3072 powerButtonIface->register_property(
3073 "ButtonMasked", false, [](const bool requested, bool& current) {
3074 if (requested)
3075 {
3076 if (powerButtonMask)
3077 {
3078 return 1;
3079 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003080 if (!setGPIOOutput(powerOutConfig.lineName,
3081 !powerOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303082 powerButtonMask))
3083 {
3084 throw std::runtime_error("Failed to request GPIO");
3085 return 0;
3086 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003087 lg2::info("Power Button Masked.");
Priyatharshan P70120512020-09-16 18:47:20 +05303088 }
3089 else
3090 {
3091 if (!powerButtonMask)
3092 {
3093 return 1;
3094 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003095 lg2::info("Power Button Un-masked");
Priyatharshan P70120512020-09-16 18:47:20 +05303096 powerButtonMask.reset();
3097 }
3098 // Update the mask setting
3099 current = requested;
3100 return 1;
3101 });
3102
3103 // Check power button state
3104 bool powerButtonPressed;
3105 if (powerButtonConfig.type == ConfigType::GPIO)
3106 {
3107 powerButtonPressed = powerButtonLine.get_value() == 0;
3108 }
3109 else
3110 {
3111 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3112 }
3113
3114 powerButtonIface->register_property("ButtonPressed",
3115 powerButtonPressed);
3116
3117 powerButtonIface->initialize();
3118 }
3119
3120 if (!resetButtonConfig.lineName.empty())
3121 {
3122 // Reset Button Interface
3123
Lei YU92caa4c2021-02-23 16:59:25 +08003124 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003125 "/xyz/openbmc_project/chassis/buttons/reset",
3126 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003127
Lei YU92caa4c2021-02-23 16:59:25 +08003128 resetButtonIface->register_property(
John Wang6c090072020-09-30 13:32:16 +08003129 "ButtonMasked", false, [](const bool requested, bool& current) {
3130 if (requested)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003131 {
Lei YU92caa4c2021-02-23 16:59:25 +08003132 if (resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003133 {
3134 return 1;
3135 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003136 if (!setGPIOOutput(resetOutConfig.lineName,
3137 !resetOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303138 resetButtonMask))
John Wang6c090072020-09-30 13:32:16 +08003139 {
3140 throw std::runtime_error("Failed to request GPIO");
3141 return 0;
3142 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003143 lg2::info("Reset Button Masked.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003144 }
John Wang6c090072020-09-30 13:32:16 +08003145 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003146 {
Lei YU92caa4c2021-02-23 16:59:25 +08003147 if (!resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003148 {
3149 return 1;
3150 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003151 lg2::info("Reset Button Un-masked");
Lei YU92caa4c2021-02-23 16:59:25 +08003152 resetButtonMask.reset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003153 }
John Wang6c090072020-09-30 13:32:16 +08003154 // Update the mask setting
3155 current = requested;
3156 return 1;
3157 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003158
John Wang6c090072020-09-30 13:32:16 +08003159 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303160 bool resetButtonPressed;
3161 if (resetButtonConfig.type == ConfigType::GPIO)
3162 {
3163 resetButtonPressed = resetButtonLine.get_value() == 0;
3164 }
3165 else
3166 {
3167 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3168 }
3169
Lei YU92caa4c2021-02-23 16:59:25 +08003170 resetButtonIface->register_property("ButtonPressed",
3171 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003172
Lei YU92caa4c2021-02-23 16:59:25 +08003173 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003174 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003175
Lei YU92caa4c2021-02-23 16:59:25 +08003176 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003177 {
3178 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003179 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003180 "/xyz/openbmc_project/chassis/buttons/nmi",
3181 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003182
Lei YU92caa4c2021-02-23 16:59:25 +08003183 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003184 "ButtonMasked", false, [](const bool requested, bool& current) {
Lei YU92caa4c2021-02-23 16:59:25 +08003185 if (nmiButtonMasked == requested)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003186 {
3187 // NMI button mask is already set as requested, so no change
3188 return 1;
3189 }
3190 if (requested)
3191 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003192 lg2::info("NMI Button Masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003193 nmiButtonMasked = true;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003194 }
3195 else
3196 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003197 lg2::info("NMI Button Un-masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003198 nmiButtonMasked = false;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003199 }
3200 // Update the mask setting
Lei YU92caa4c2021-02-23 16:59:25 +08003201 current = nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003202 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003203 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003204
Vijay Khemka33a532d2019-11-14 16:50:35 -08003205 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303206 bool nmiButtonPressed;
3207 if (nmiButtonConfig.type == ConfigType::GPIO)
3208 {
3209 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3210 }
3211 else
3212 {
3213 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3214 }
3215
Lei YU92caa4c2021-02-23 16:59:25 +08003216 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003217
Lei YU92caa4c2021-02-23 16:59:25 +08003218 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003219 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003220
Lei YU92caa4c2021-02-23 16:59:25 +08003221 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003222 {
3223 // NMI out Service
3224 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003225 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003226
Vijay Khemka33a532d2019-11-14 16:50:35 -08003227 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303228 nmiOutIface = nmiOutServer.add_interface(
3229 "/xyz/openbmc_project/control/host" + node + "/nmi",
3230 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003231 nmiOutIface->register_method("NMI", nmiReset);
3232 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003233 }
Chen Yugang174ec662019-08-19 19:58:49 +08003234
Lei YU92caa4c2021-02-23 16:59:25 +08003235 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003236 {
3237 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003238 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003239 "/xyz/openbmc_project/chassis/buttons/id",
3240 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003241
Vijay Khemka33a532d2019-11-14 16:50:35 -08003242 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303243 bool idButtonPressed;
3244 if (idButtonConfig.type == ConfigType::GPIO)
3245 {
3246 idButtonPressed = idButtonLine.get_value() == 0;
3247 }
3248 else
3249 {
3250 idButtonPressed = getProperty(idButtonConfig) == 0;
3251 }
3252
Lei YU92caa4c2021-02-23 16:59:25 +08003253 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003254
Lei YU92caa4c2021-02-23 16:59:25 +08003255 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003256 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003257
3258 // OS State Service
3259 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003260 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003261
3262 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003263 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003264 "/xyz/openbmc_project/state/os",
3265 "xyz.openbmc_project.State.OperatingSystem.Status");
3266
3267 // Get the initial OS state based on POST complete
3268 // 0: Asserted, OS state is "Standby" (ready to boot)
3269 // 1: De-Asserted, OS state is "Inactive"
Tim Lee86239182021-12-23 11:46:01 +08003270 OperatingSystemStateStage osState;
Priyatharshan P70120512020-09-16 18:47:20 +05303271 if (postCompleteConfig.type == ConfigType::GPIO)
3272 {
Tim Lee86239182021-12-23 11:46:01 +08003273 osState = postCompleteLine.get_value() > 0
3274 ? OperatingSystemStateStage::Inactive
3275 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303276 }
3277 else
3278 {
Tim Lee86239182021-12-23 11:46:01 +08003279 osState = getProperty(postCompleteConfig) > 0
3280 ? OperatingSystemStateStage::Inactive
3281 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303282 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003283
Tim Lee86239182021-12-23 11:46:01 +08003284 osIface->register_property(
3285 "OperatingSystemState",
3286 std::string(getOperatingSystemStateStage(osState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003287
Lei YU92caa4c2021-02-23 16:59:25 +08003288 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003289
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003290 // Restart Cause Service
3291 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003292 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003293
3294 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003295 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303296 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003297 "xyz.openbmc_project.Control.Host.RestartCause");
3298
Lei YU92caa4c2021-02-23 16:59:25 +08003299 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003300 "RestartCause",
3301 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3302
Lei YU92caa4c2021-02-23 16:59:25 +08003303 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003304 "RequestedRestartCause",
3305 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3306 [](const std::string& requested, std::string& resp) {
3307 if (requested ==
3308 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3309 {
Lei YU92caa4c2021-02-23 16:59:25 +08003310 addRestartCause(RestartCause::watchdog);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003311 }
3312 else
3313 {
3314 throw std::invalid_argument(
3315 "Unrecognized RestartCause Request");
3316 return 0;
3317 }
3318
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003319 lg2::info("RestartCause requested: {RESTART_CAUSE}",
3320 "RESTART_CAUSE", requested);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003321 resp = requested;
3322 return 1;
3323 });
3324
Lei YU92caa4c2021-02-23 16:59:25 +08003325 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003326
Lei YU92caa4c2021-02-23 16:59:25 +08003327 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003328
Lei YU92caa4c2021-02-23 16:59:25 +08003329 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003330
3331 return 0;
3332}