blob: 7362c6c1a74448224029b3cff9e913d88f63deb1 [file] [log] [blame]
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001/*
2// Copyright (c) 2018-2019 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +030016#include "power_control.hpp"
17
Ed Tanousf61ca6f2019-08-15 15:09:05 -070018#include <sys/sysinfo.h>
19#include <systemd/sd-journal.h>
20
Jason M. Billse63dea02020-08-27 12:07:35 -070021#include <boost/asio/io_service.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070022#include <boost/asio/posix/stream_descriptor.hpp>
Jason M. Billse63dea02020-08-27 12:07:35 -070023#include <boost/asio/steady_timer.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070024#include <boost/container/flat_map.hpp>
Jason M. Bills7d4aaac2019-09-19 14:03:44 -070025#include <boost/container/flat_set.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070026#include <gpiod.hpp>
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053027#include <nlohmann/json.hpp>
Jason M. Billsc46ebb42021-11-10 11:41:31 -080028#include <phosphor-logging/lg2.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070029#include <sdbusplus/asio/object_server.hpp>
Vijay Khemka2b6f4422020-05-29 11:13:23 -070030
31#include <filesystem>
32#include <fstream>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070033#include <string_view>
34
35namespace power_control
36{
37static boost::asio::io_service io;
38std::shared_ptr<sdbusplus::asio::connection> conn;
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +030039PersistentState appState;
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +030040PowerRestoreController powerRestore(io);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053041
42static std::string node = "0";
Andrei Kartashev3efcf372021-12-29 15:32:17 +030043static const std::string appName = "power-control";
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053044
Priyatharshan P70120512020-09-16 18:47:20 +053045enum class DbusConfigType
46{
47 name = 1,
48 path,
49 interface,
50 property
51};
52boost::container::flat_map<DbusConfigType, std::string> dbusParams = {
53 {DbusConfigType::name, "DbusName"},
54 {DbusConfigType::path, "Path"},
55 {DbusConfigType::interface, "Interface"},
56 {DbusConfigType::property, "Property"}};
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053057
Priyatharshan P70120512020-09-16 18:47:20 +053058enum class ConfigType
59{
60 GPIO = 1,
61 DBUS
62};
63
64struct ConfigData
65{
66 std::string name;
67 std::string lineName;
68 std::string dbusName;
69 std::string path;
70 std::string interface;
Jean-Marie Verdun50937e72021-08-31 09:15:49 -070071 bool polarity;
Priyatharshan P70120512020-09-16 18:47:20 +053072 ConfigType type;
73};
74
75static ConfigData powerOutConfig;
76static ConfigData powerOkConfig;
77static ConfigData resetOutConfig;
78static ConfigData nmiOutConfig;
79static ConfigData sioPwrGoodConfig;
80static ConfigData sioOnControlConfig;
81static ConfigData sioS5Config;
82static ConfigData postCompleteConfig;
83static ConfigData powerButtonConfig;
84static ConfigData resetButtonConfig;
85static ConfigData idButtonConfig;
86static ConfigData nmiButtonConfig;
Naveen Moses117c34e2021-05-26 20:10:51 +053087static ConfigData slotPowerConfig;
88
Priyatharshan P70120512020-09-16 18:47:20 +053089// map for storing list of gpio parameters whose config are to be read from x86
90// power control json config
91boost::container::flat_map<std::string, ConfigData*> powerSignalMap = {
92 {"PowerOut", &powerOutConfig},
93 {"PowerOk", &powerOkConfig},
94 {"ResetOut", &resetOutConfig},
95 {"NMIOut", &nmiOutConfig},
96 {"SioPowerGood", &sioPwrGoodConfig},
97 {"SioOnControl", &sioOnControlConfig},
98 {"SIOS5", &sioS5Config},
99 {"PostComplete", &postCompleteConfig},
100 {"PowerButton", &powerButtonConfig},
101 {"ResetButton", &resetButtonConfig},
102 {"IdButton", &idButtonConfig},
Naveen Moses117c34e2021-05-26 20:10:51 +0530103 {"NMIButton", &nmiButtonConfig},
104 {"SlotPower", &slotPowerConfig}};
Priyatharshan P70120512020-09-16 18:47:20 +0530105
106static std::string hostDbusName = "xyz.openbmc_project.State.Host";
107static std::string chassisDbusName = "xyz.openbmc_project.State.Chassis";
108static std::string osDbusName = "xyz.openbmc_project.State.OperatingSystem";
109static std::string buttonDbusName = "xyz.openbmc_project.Chassis.Buttons";
110static std::string nmiDbusName = "xyz.openbmc_project.Control.Host.NMI";
111static std::string rstCauseDbusName =
112 "xyz.openbmc_project.Control.Host.RestartCause";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700113static std::shared_ptr<sdbusplus::asio::dbus_interface> hostIface;
114static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700115#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -0700116static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSysIface;
Naveen Moses117c34e2021-05-26 20:10:51 +0530117static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSlotIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700118#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700119static std::shared_ptr<sdbusplus::asio::dbus_interface> powerButtonIface;
120static std::shared_ptr<sdbusplus::asio::dbus_interface> resetButtonIface;
121static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiButtonIface;
122static std::shared_ptr<sdbusplus::asio::dbus_interface> osIface;
123static std::shared_ptr<sdbusplus::asio::dbus_interface> idButtonIface;
Chen Yugang174ec662019-08-19 19:58:49 +0800124static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiOutIface;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700125static std::shared_ptr<sdbusplus::asio::dbus_interface> restartCauseIface;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700126
127static gpiod::line powerButtonMask;
128static gpiod::line resetButtonMask;
129static bool nmiButtonMasked = false;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700130
Priyatharshan P70120512020-09-16 18:47:20 +0530131// This map contains all timer values that are to be read from json config
132boost::container::flat_map<std::string, int> TimerMap = {
Jason M. Billsaeefe042021-09-08 14:56:11 -0700133 {"PowerPulseMs", 200},
134 {"ForceOffPulseMs", 15000},
135 {"ResetPulseMs", 500},
136 {"PowerCycleMs", 5000},
137 {"SioPowerGoodWatchdogMs", 1000},
138 {"PsPowerOKWatchdogMs", 8000},
139 {"GracefulPowerOffS", (5 * 60)},
140 {"WarmResetCheckMs", 500},
141 {"PowerOffSaveMs", 7000},
142 {"SlotPowerCycleMs", 200}};
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700143
144static bool nmiEnabled = true;
Priyatharshan P19c47a32020-08-12 18:16:43 +0530145static bool sioEnabled = true;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700146
147// Timers
148// Time holding GPIOs asserted
149static boost::asio::steady_timer gpioAssertTimer(io);
150// Time between off and on during a power cycle
151static boost::asio::steady_timer powerCycleTimer(io);
152// Time OS gracefully powering off
153static boost::asio::steady_timer gracefulPowerOffTimer(io);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700154// Time the warm reset check
155static boost::asio::steady_timer warmResetCheckTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700156// Time power supply power OK assertion on power-on
157static boost::asio::steady_timer psPowerOKWatchdogTimer(io);
158// Time SIO power good assertion on power-on
159static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io);
160// Time power-off state save for power loss tracking
161static boost::asio::steady_timer powerStateSaveTimer(io);
162// POH timer
163static boost::asio::steady_timer pohCounterTimer(io);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700164// Time when to allow restart cause updates
165static boost::asio::steady_timer restartCauseTimer(io);
Naveen Moses117c34e2021-05-26 20:10:51 +0530166static boost::asio::steady_timer slotPowerCycleTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700167
168// GPIO Lines and Event Descriptors
169static gpiod::line psPowerOKLine;
170static boost::asio::posix::stream_descriptor psPowerOKEvent(io);
171static gpiod::line sioPowerGoodLine;
172static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io);
173static gpiod::line sioOnControlLine;
174static boost::asio::posix::stream_descriptor sioOnControlEvent(io);
175static gpiod::line sioS5Line;
176static boost::asio::posix::stream_descriptor sioS5Event(io);
177static gpiod::line powerButtonLine;
178static boost::asio::posix::stream_descriptor powerButtonEvent(io);
179static gpiod::line resetButtonLine;
180static boost::asio::posix::stream_descriptor resetButtonEvent(io);
181static gpiod::line nmiButtonLine;
182static boost::asio::posix::stream_descriptor nmiButtonEvent(io);
183static gpiod::line idButtonLine;
184static boost::asio::posix::stream_descriptor idButtonEvent(io);
185static gpiod::line postCompleteLine;
186static boost::asio::posix::stream_descriptor postCompleteEvent(io);
187static gpiod::line nmiOutLine;
Naveen Moses117c34e2021-05-26 20:10:51 +0530188static gpiod::line slotPowerLine;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700189
190static constexpr uint8_t beepPowerFail = 8;
191
192static void beep(const uint8_t& beepPriority)
193{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800194 lg2::info("Beep with priority: {BEEP_PRIORITY}", "BEEP_PRIORITY",
195 beepPriority);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700196
197 conn->async_method_call(
198 [](boost::system::error_code ec) {
199 if (ec)
200 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800201 lg2::error(
202 "beep returned error with async_method_call (ec = {ERROR_MSG})",
203 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700204 return;
205 }
206 },
207 "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
208 "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
209}
210
Tim Lee86239182021-12-23 11:46:01 +0800211enum class OperatingSystemStateStage
212{
213 Inactive,
214 Standby,
215};
216static constexpr std::string_view
217 getOperatingSystemStateStage(const OperatingSystemStateStage stage)
218{
219 switch (stage)
220 {
221 case OperatingSystemStateStage::Inactive:
222 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
223 break;
224 case OperatingSystemStateStage::Standby:
225 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Standby";
226 break;
227 default:
228 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
229 break;
230 }
231};
232static void setOperatingSystemState(const OperatingSystemStateStage stage)
233{
234 osIface->set_property("OperatingSystemState",
235 std::string(getOperatingSystemStateStage(stage)));
236
237 lg2::info("Moving os state to {STATE} stage", "STATE",
238 getOperatingSystemStateStage(stage));
239}
240
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700241enum class PowerState
242{
243 on,
244 waitForPSPowerOK,
245 waitForSIOPowerGood,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700246 off,
247 transitionToOff,
248 gracefulTransitionToOff,
249 cycleOff,
250 transitionToCycleOff,
251 gracefulTransitionToCycleOff,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700252 checkForWarmReset,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700253};
254static PowerState powerState;
255static std::string getPowerStateName(PowerState state)
256{
257 switch (state)
258 {
259 case PowerState::on:
260 return "On";
261 break;
262 case PowerState::waitForPSPowerOK:
263 return "Wait for Power Supply Power OK";
264 break;
265 case PowerState::waitForSIOPowerGood:
266 return "Wait for SIO Power Good";
267 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700268 case PowerState::off:
269 return "Off";
270 break;
271 case PowerState::transitionToOff:
272 return "Transition to Off";
273 break;
274 case PowerState::gracefulTransitionToOff:
275 return "Graceful Transition to Off";
276 break;
277 case PowerState::cycleOff:
278 return "Power Cycle Off";
279 break;
280 case PowerState::transitionToCycleOff:
281 return "Transition to Power Cycle Off";
282 break;
283 case PowerState::gracefulTransitionToCycleOff:
284 return "Graceful Transition to Power Cycle Off";
285 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700286 case PowerState::checkForWarmReset:
287 return "Check for Warm Reset";
288 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700289 default:
290 return "unknown state: " + std::to_string(static_cast<int>(state));
291 break;
292 }
293}
294static void logStateTransition(const PowerState state)
295{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800296 lg2::info("Host{HOST}: Moving to \"{STATE}\" state", "HOST", node, "STATE",
297 getPowerStateName(state));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700298}
299
300enum class Event
301{
302 psPowerOKAssert,
303 psPowerOKDeAssert,
304 sioPowerGoodAssert,
305 sioPowerGoodDeAssert,
306 sioS5Assert,
307 sioS5DeAssert,
Jason M. Billsfb957332021-01-28 13:18:46 -0800308 pltRstAssert,
309 pltRstDeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700310 postCompleteAssert,
311 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700312 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700313 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700314 powerCycleTimerExpired,
315 psPowerOKWatchdogTimerExpired,
316 sioPowerGoodWatchdogTimerExpired,
317 gracefulPowerOffTimerExpired,
318 powerOnRequest,
319 powerOffRequest,
320 powerCycleRequest,
321 resetRequest,
322 gracefulPowerOffRequest,
323 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700324 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700325};
326static std::string getEventName(Event event)
327{
328 switch (event)
329 {
330 case Event::psPowerOKAssert:
331 return "power supply power OK assert";
332 break;
333 case Event::psPowerOKDeAssert:
334 return "power supply power OK de-assert";
335 break;
336 case Event::sioPowerGoodAssert:
337 return "SIO power good assert";
338 break;
339 case Event::sioPowerGoodDeAssert:
340 return "SIO power good de-assert";
341 break;
342 case Event::sioS5Assert:
343 return "SIO S5 assert";
344 break;
345 case Event::sioS5DeAssert:
346 return "SIO S5 de-assert";
347 break;
Jason M. Billsfb957332021-01-28 13:18:46 -0800348 case Event::pltRstAssert:
349 return "PLT_RST assert";
350 break;
351 case Event::pltRstDeAssert:
352 return "PLT_RST de-assert";
353 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700354 case Event::postCompleteAssert:
355 return "POST Complete assert";
356 break;
357 case Event::postCompleteDeAssert:
358 return "POST Complete de-assert";
359 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700360 case Event::powerButtonPressed:
361 return "power button pressed";
362 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700363 case Event::resetButtonPressed:
364 return "reset button pressed";
365 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700366 case Event::powerCycleTimerExpired:
367 return "power cycle timer expired";
368 break;
369 case Event::psPowerOKWatchdogTimerExpired:
370 return "power supply power OK watchdog timer expired";
371 break;
372 case Event::sioPowerGoodWatchdogTimerExpired:
373 return "SIO power good watchdog timer expired";
374 break;
375 case Event::gracefulPowerOffTimerExpired:
376 return "graceful power-off timer expired";
377 break;
378 case Event::powerOnRequest:
379 return "power-on request";
380 break;
381 case Event::powerOffRequest:
382 return "power-off request";
383 break;
384 case Event::powerCycleRequest:
385 return "power-cycle request";
386 break;
387 case Event::resetRequest:
388 return "reset request";
389 break;
390 case Event::gracefulPowerOffRequest:
391 return "graceful power-off request";
392 break;
393 case Event::gracefulPowerCycleRequest:
394 return "graceful power-cycle request";
395 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700396 case Event::warmResetDetected:
397 return "warm reset detected";
398 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700399 default:
400 return "unknown event: " + std::to_string(static_cast<int>(event));
401 break;
402 }
403}
404static void logEvent(const std::string_view stateHandler, const Event event)
405{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800406 lg2::info("{STATE_HANDLER}: {EVENT} event received", "STATE_HANDLER",
407 stateHandler, "EVENT", getEventName(event));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700408}
409
410// Power state handlers
411static void powerStateOn(const Event event);
412static void powerStateWaitForPSPowerOK(const Event event);
413static void powerStateWaitForSIOPowerGood(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700414static void powerStateOff(const Event event);
415static void powerStateTransitionToOff(const Event event);
416static void powerStateGracefulTransitionToOff(const Event event);
417static void powerStateCycleOff(const Event event);
418static void powerStateTransitionToCycleOff(const Event event);
419static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700420static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700421
422static std::function<void(const Event)> getPowerStateHandler(PowerState state)
423{
424 switch (state)
425 {
426 case PowerState::on:
427 return powerStateOn;
428 break;
429 case PowerState::waitForPSPowerOK:
430 return powerStateWaitForPSPowerOK;
431 break;
432 case PowerState::waitForSIOPowerGood:
433 return powerStateWaitForSIOPowerGood;
434 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700435 case PowerState::off:
436 return powerStateOff;
437 break;
438 case PowerState::transitionToOff:
439 return powerStateTransitionToOff;
440 break;
441 case PowerState::gracefulTransitionToOff:
442 return powerStateGracefulTransitionToOff;
443 break;
444 case PowerState::cycleOff:
445 return powerStateCycleOff;
446 break;
447 case PowerState::transitionToCycleOff:
448 return powerStateTransitionToCycleOff;
449 break;
450 case PowerState::gracefulTransitionToCycleOff:
451 return powerStateGracefulTransitionToCycleOff;
452 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700453 case PowerState::checkForWarmReset:
454 return powerStateCheckForWarmReset;
455 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700456 default:
Zev Weiss047bcb52020-08-20 21:28:11 +0000457 return nullptr;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700458 break;
459 }
460};
461
462static void sendPowerControlEvent(const Event event)
463{
464 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
465 if (handler == nullptr)
466 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800467 lg2::error("Failed to find handler for power state: {STATE}", "STATE",
468 static_cast<int>(powerState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700469 return;
470 }
471 handler(event);
472}
473
474static uint64_t getCurrentTimeMs()
475{
476 struct timespec time = {};
477
478 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
479 {
480 return 0;
481 }
482 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
483 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
484
485 return currentTimeMs;
486}
487
488static constexpr std::string_view getHostState(const PowerState state)
489{
490 switch (state)
491 {
492 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700493 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700494 case PowerState::gracefulTransitionToCycleOff:
495 return "xyz.openbmc_project.State.Host.HostState.Running";
496 break;
497 case PowerState::waitForPSPowerOK:
498 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700499 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700500 case PowerState::transitionToOff:
501 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700502 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700503 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700504 return "xyz.openbmc_project.State.Host.HostState.Off";
505 break;
506 default:
507 return "";
508 break;
509 }
510};
511static constexpr std::string_view getChassisState(const PowerState state)
512{
513 switch (state)
514 {
515 case PowerState::on:
516 case PowerState::transitionToOff:
517 case PowerState::gracefulTransitionToOff:
518 case PowerState::transitionToCycleOff:
519 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700520 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700521 return "xyz.openbmc_project.State.Chassis.PowerState.On";
522 break;
523 case PowerState::waitForPSPowerOK:
524 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700525 case PowerState::off:
526 case PowerState::cycleOff:
527 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
528 break;
529 default:
530 return "";
531 break;
532 }
533};
Naveen Moses117c34e2021-05-26 20:10:51 +0530534#ifdef CHASSIS_SYSTEM_RESET
535enum class SlotPowerState
536{
537 on,
538 off,
539};
540static SlotPowerState slotPowerState;
541static constexpr std::string_view getSlotState(const SlotPowerState state)
542{
543 switch (state)
544 {
545 case SlotPowerState::on:
546 return "xyz.openbmc_project.State.Chassis.PowerState.On";
547 break;
548 case SlotPowerState::off:
549 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
550 break;
551 default:
552 return "";
553 break;
554 }
555};
556static void setSlotPowerState(const SlotPowerState state)
557{
558 slotPowerState = state;
559 chassisSlotIface->set_property("CurrentPowerState",
560 std::string(getSlotState(slotPowerState)));
561 chassisSlotIface->set_property("LastStateChangeTime", getCurrentTimeMs());
562}
563#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700564static void savePowerState(const PowerState state)
565{
566 powerStateSaveTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -0700567 std::chrono::milliseconds(TimerMap["PowerOffSaveMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700568 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
569 if (ec)
570 {
571 // operation_aborted is expected if timer is canceled before
572 // completion.
573 if (ec != boost::asio::error::operation_aborted)
574 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800575 lg2::error("Power-state save async_wait failed: {ERROR_MSG}",
576 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700577 }
578 return;
579 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300580 appState.set(PersistentState::Params::PowerState,
581 std::string{getChassisState(state)});
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700582 });
583}
584static void setPowerState(const PowerState state)
585{
586 powerState = state;
587 logStateTransition(state);
588
589 hostIface->set_property("CurrentHostState",
590 std::string(getHostState(powerState)));
591
592 chassisIface->set_property("CurrentPowerState",
593 std::string(getChassisState(powerState)));
594 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
595
596 // Save the power state for the restore policy
597 savePowerState(state);
598}
599
600enum class RestartCause
601{
602 command,
603 resetButton,
604 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700605 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700606 powerPolicyOn,
607 powerPolicyRestore,
608 softReset,
609};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700610static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700611static std::string getRestartCause(RestartCause cause)
612{
613 switch (cause)
614 {
615 case RestartCause::command:
616 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
617 break;
618 case RestartCause::resetButton:
619 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
620 break;
621 case RestartCause::powerButton:
622 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
623 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700624 case RestartCause::watchdog:
625 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
626 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700627 case RestartCause::powerPolicyOn:
Jason M. Bills418ce112021-09-08 15:15:05 -0700628 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyAlwaysOn";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700629 break;
630 case RestartCause::powerPolicyRestore:
Jason M. Bills418ce112021-09-08 15:15:05 -0700631 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyPreviousState";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700632 break;
633 case RestartCause::softReset:
634 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
635 break;
636 default:
637 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
638 break;
639 }
640}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700641static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700642{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700643 // Add this to the set of causes for this restart
644 causeSet.insert(cause);
645}
646static void clearRestartCause()
647{
648 // Clear the set for the next restart
649 causeSet.clear();
650}
651static void setRestartCauseProperty(const std::string& cause)
652{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800653 lg2::info("RestartCause set to {RESTART_CAUSE}", "RESTART_CAUSE", cause);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700654 restartCauseIface->set_property("RestartCause", cause);
655}
Rashmi RV89f61312020-01-22 15:41:50 +0530656
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300657#ifdef USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +0530658static void resetACBootProperty()
659{
660 if ((causeSet.contains(RestartCause::command)) ||
661 (causeSet.contains(RestartCause::softReset)))
662 {
663 conn->async_method_call(
664 [](boost::system::error_code ec) {
665 if (ec)
666 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800667 lg2::error("failed to reset ACBoot property");
Rashmi RV89f61312020-01-22 15:41:50 +0530668 }
669 },
670 "xyz.openbmc_project.Settings",
671 "/xyz/openbmc_project/control/host0/ac_boot",
672 "org.freedesktop.DBus.Properties", "Set",
673 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
674 std::variant<std::string>{"False"});
675 }
676}
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300677#endif // USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +0530678
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700679static void setRestartCause()
680{
681 // Determine the actual restart cause based on the set of causes
682 std::string restartCause =
683 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
684 if (causeSet.contains(RestartCause::watchdog))
685 {
686 restartCause = getRestartCause(RestartCause::watchdog);
687 }
688 else if (causeSet.contains(RestartCause::command))
689 {
690 restartCause = getRestartCause(RestartCause::command);
691 }
692 else if (causeSet.contains(RestartCause::resetButton))
693 {
694 restartCause = getRestartCause(RestartCause::resetButton);
695 }
696 else if (causeSet.contains(RestartCause::powerButton))
697 {
698 restartCause = getRestartCause(RestartCause::powerButton);
699 }
700 else if (causeSet.contains(RestartCause::powerPolicyOn))
701 {
702 restartCause = getRestartCause(RestartCause::powerPolicyOn);
703 }
704 else if (causeSet.contains(RestartCause::powerPolicyRestore))
705 {
706 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
707 }
708 else if (causeSet.contains(RestartCause::softReset))
709 {
710 restartCause = getRestartCause(RestartCause::softReset);
711 }
712
713 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700714}
715
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700716static void systemPowerGoodFailedLog()
717{
718 sd_journal_send(
719 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
720 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
721 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700722 TimerMap["SioPowerGoodWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700723}
724
725static void psPowerOKFailedLog()
726{
727 sd_journal_send(
728 "MESSAGE=PowerControl: power supply power good failed to assert",
729 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
730 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700731 TimerMap["PsPowerOKWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700732}
733
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700734static void powerRestorePolicyLog()
735{
736 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
737 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
738 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
739}
740
741static void powerButtonPressLog()
742{
743 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
744 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
745 "OpenBMC.0.1.PowerButtonPressed", NULL);
746}
747
748static void resetButtonPressLog()
749{
750 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
751 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
752 "OpenBMC.0.1.ResetButtonPressed", NULL);
753}
754
755static void nmiButtonPressLog()
756{
757 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
758 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
759 "OpenBMC.0.1.NMIButtonPressed", NULL);
760}
761
762static void nmiDiagIntLog()
763{
764 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
765 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
766 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
767}
768
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300769PersistentState::PersistentState()
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700770{
771 // create the power control directory if it doesn't exist
772 std::error_code ec;
773 if (!(std::filesystem::create_directories(powerControlDir, ec)))
774 {
775 if (ec.value() != 0)
776 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800777 lg2::error("failed to create {DIR_NAME}: {ERROR_MSG}", "DIR_NAME",
778 powerControlDir.string(), "ERROR_MSG", ec.message());
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300779 throw std::runtime_error("Failed to create state directory");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700780 }
781 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300782
783 // read saved state, it's ok, if the file doesn't exists
784 std::ifstream appStateStream(powerControlDir / stateFile);
785 if (!appStateStream.is_open())
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700786 {
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300787 lg2::info("Cannot open state file \'{PATH}\'", "PATH",
788 std::string(powerControlDir / stateFile));
789 stateData = nlohmann::json({});
790 return;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700791 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300792 try
793 {
794 appStateStream >> stateData;
795 if (stateData.is_discarded())
796 {
797 lg2::info("Cannot parse state file \'{PATH}\'", "PATH",
798 std::string(powerControlDir / stateFile));
799 stateData = nlohmann::json({});
800 return;
801 }
802 }
803 catch (const std::exception& ex)
804 {
805 lg2::info("Cannot read state file \'{PATH}\'", "PATH",
806 std::string(powerControlDir / stateFile));
807 stateData = nlohmann::json({});
808 return;
809 }
810}
811PersistentState::~PersistentState()
812{
813 saveState();
814}
815const std::string PersistentState::get(Params parameter)
816{
817 auto val = stateData.find(getName(parameter));
818 if (val != stateData.end())
819 {
820 return val->get<std::string>();
821 }
822 return getDefault(parameter);
823}
824void PersistentState::set(Params parameter, const std::string& value)
825{
826 stateData[getName(parameter)] = value;
827 saveState();
828}
829
830const std::string PersistentState::getName(const Params parameter)
831{
832 switch (parameter)
833 {
834 case Params::PowerState:
835 return "PowerState";
836 }
837 return "";
838}
839const std::string PersistentState::getDefault(const Params parameter)
840{
841 switch (parameter)
842 {
843 case Params::PowerState:
844 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
845 }
846 return "";
847}
848void PersistentState::saveState()
849{
850 std::ofstream appStateStream(powerControlDir / stateFile, std::ios::trunc);
851 if (!appStateStream.is_open())
852 {
853 lg2::error("Cannot write state file \'{PATH}\'", "PATH",
854 std::string(powerControlDir / stateFile));
855 return;
856 }
857 appStateStream << stateData.dump(indentationSize);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700858}
859
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300860static constexpr char const* setingsService = "xyz.openbmc_project.Settings";
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300861static constexpr char const* powerRestorePolicyIface =
862 "xyz.openbmc_project.Control.Power.RestorePolicy";
863#ifdef USE_ACBOOT
864static constexpr char const* powerACBootObject =
865 "/xyz/openbmc_project/control/host0/ac_boot";
866static constexpr char const* powerACBootIface =
867 "xyz.openbmc_project.Common.ACBoot";
868#endif // USE_ACBOOT
869
870namespace match_rules = sdbusplus::bus::match::rules;
871
872static int powerRestoreConfigHandler(sd_bus_message* m, void* context,
873 sd_bus_error*)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700874{
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300875 if (context == nullptr || m == nullptr)
876 {
877 throw std::runtime_error("Invalid match");
878 }
Patrick Williams439b9c32022-07-22 19:26:53 -0500879 sdbusplus::message_t message(m);
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300880 PowerRestoreController* powerRestore =
881 static_cast<PowerRestoreController*>(context);
882
883 if (std::string(message.get_member()) == "InterfacesAdded")
884 {
885 sdbusplus::message::object_path path;
886 boost::container::flat_map<std::string, dbusPropertiesList> data;
887
888 message.read(path, data);
889
890 for (auto& [iface, properties] : data)
891 {
892 if ((iface == powerRestorePolicyIface)
893#ifdef USE_ACBOOT
894 || (iface == powerACBootIface)
895#endif // USE_ACBOOT
896 )
897 {
898 powerRestore->setProperties(properties);
899 }
900 }
901 }
902 else if (std::string(message.get_member()) == "PropertiesChanged")
903 {
904 std::string interfaceName;
905 dbusPropertiesList propertiesChanged;
906
907 message.read(interfaceName, propertiesChanged);
908
909 powerRestore->setProperties(propertiesChanged);
910 }
911 return 1;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700912}
913
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300914void PowerRestoreController::run()
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700915{
Karthikeyan Pasupathib38fe832022-07-19 19:53:38 +0530916 std::string powerRestorePolicyObject =
917 "/xyz/openbmc_project/control/host" + node + "/power_restore_policy";
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300918 powerRestorePolicyLog();
919 // this list only needs to be created once
920 if (matches.empty())
921 {
922 matches.emplace_back(
923 *conn,
924 match_rules::interfacesAdded() +
925 match_rules::argNpath(0, powerRestorePolicyObject) +
926 match_rules::sender(setingsService),
927 powerRestoreConfigHandler, this);
928#ifdef USE_ACBOOT
929 matches.emplace_back(*conn,
930 match_rules::interfacesAdded() +
931 match_rules::argNpath(0, powerACBootObject) +
932 match_rules::sender(setingsService),
933 powerRestoreConfigHandler, this);
934 matches.emplace_back(*conn,
935 match_rules::propertiesChanged(powerACBootObject,
936 powerACBootIface) +
937 match_rules::sender(setingsService),
938 powerRestoreConfigHandler, this);
939#endif // USE_ACBOOT
940 }
941
942 // Check if it's already on DBus
943 conn->async_method_call(
944 [this](boost::system::error_code ec,
945 const dbusPropertiesList properties) {
946 if (ec)
947 {
948 return;
949 }
950 setProperties(properties);
951 },
952 setingsService, powerRestorePolicyObject,
953 "org.freedesktop.DBus.Properties", "GetAll", powerRestorePolicyIface);
954
955#ifdef USE_ACBOOT
956 // Check if it's already on DBus
957 conn->async_method_call(
958 [this](boost::system::error_code ec,
959 const dbusPropertiesList properties) {
960 if (ec)
961 {
962 return;
963 }
964 setProperties(properties);
965 },
966 setingsService, powerACBootObject, "org.freedesktop.DBus.Properties",
967 "GetAll", powerACBootIface);
968#endif
969}
970
971void PowerRestoreController::setProperties(const dbusPropertiesList& props)
972{
973 for (auto& [property, propValue] : props)
974 {
975 if (property == "PowerRestorePolicy")
976 {
977 const std::string* value = std::get_if<std::string>(&propValue);
978 if (value == nullptr)
979 {
980 lg2::error("Unable to read Power Restore Policy");
981 continue;
982 }
983 powerRestorePolicy = *value;
984 }
985 else if (property == "PowerRestoreDelay")
986 {
987 const uint64_t* value = std::get_if<uint64_t>(&propValue);
988 if (value == nullptr)
989 {
990 lg2::error("Unable to read Power Restore Delay");
991 continue;
992 }
993 powerRestoreDelay = *value / 1000000; // usec to sec
994 }
995#ifdef USE_ACBOOT
996 else if (property == "ACBoot")
997 {
998 const std::string* value = std::get_if<std::string>(&propValue);
999 if (value == nullptr)
1000 {
1001 lg2::error("Unable to read AC Boot status");
1002 continue;
1003 }
1004 acBoot = *value;
1005 }
1006#endif // USE_ACBOOT
1007 }
1008 invokeIfReady();
1009}
1010
1011void PowerRestoreController::invokeIfReady()
1012{
1013 if ((powerRestorePolicy.empty()) || (powerRestoreDelay < 0))
1014 {
1015 return;
1016 }
1017#ifdef USE_ACBOOT
1018 if (acBoot.empty() || acBoot == "Unknown")
1019 {
1020 return;
1021 }
1022#endif
1023
1024 matches.clear();
1025 if (!timerFired)
1026 {
1027 // Calculate the delay from now to meet the requested delay
1028 // Subtract the approximate uboot time
1029 static constexpr const int ubootSeconds = 20;
1030 int delay = powerRestoreDelay - ubootSeconds;
1031 // Subtract the time since boot
1032 struct sysinfo info = {};
1033 if (sysinfo(&info) == 0)
1034 {
1035 delay -= info.uptime;
1036 }
1037
1038 if (delay > 0)
1039 {
1040 powerRestoreTimer.expires_after(std::chrono::seconds(delay));
1041 lg2::info("Power Restore delay of {DELAY} seconds started", "DELAY",
1042 delay);
1043 powerRestoreTimer.async_wait([this](const boost::system::error_code
1044 ec) {
1045 if (ec)
1046 {
1047 // operation_aborted is expected if timer is canceled before
1048 // completion.
1049 if (ec == boost::asio::error::operation_aborted)
1050 {
1051 return;
1052 }
1053 lg2::error(
1054 "power restore policy async_wait failed: {ERROR_MSG}",
1055 "ERROR_MSG", ec.message());
1056 }
1057 else
1058 {
1059 lg2::info("Power Restore delay timer expired");
1060 }
1061 invoke();
1062 });
1063 timerFired = true;
1064 }
1065 else
1066 {
1067 invoke();
1068 }
1069 }
1070}
1071
1072void PowerRestoreController::invoke()
1073{
1074 // we want to run Power Restore only once
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001075 if (policyInvoked)
1076 {
1077 return;
1078 }
1079 policyInvoked = true;
1080
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001081 lg2::info("Invoking Power Restore Policy {POLICY}", "POLICY",
1082 powerRestorePolicy);
1083 if (powerRestorePolicy ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001084 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
1085 {
1086 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001087 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001088 }
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001089 else if (powerRestorePolicy ==
Jason M. Bills418ce112021-09-08 15:15:05 -07001090 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore")
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001091 {
1092 if (wasPowerDropped())
1093 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001094 lg2::info("Power was dropped, restoring Host On state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001095 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001096 setRestartCauseProperty(
1097 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001098 }
1099 else
1100 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001101 lg2::info("No power drop, restoring Host Off state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001102 }
1103 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -07001104 // We're done with the previous power state for the restore policy, so store
1105 // the current state
1106 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001107}
1108
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001109bool PowerRestoreController::wasPowerDropped()
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001110{
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001111 std::string state = appState.get(PersistentState::Params::PowerState);
1112 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001113}
1114
Zev Weiss676ef2c2021-09-02 21:54:02 -05001115static void waitForGPIOEvent(const std::string& name,
1116 const std::function<void(bool)>& eventHandler,
1117 gpiod::line& line,
1118 boost::asio::posix::stream_descriptor& event)
1119{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001120 event.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1121 [&name, eventHandler, &line,
1122 &event](const boost::system::error_code ec) {
1123 if (ec)
1124 {
1125 lg2::error(
1126 "{GPIO_NAME} fd handler error: {ERROR_MSG}",
1127 "GPIO_NAME", name, "ERROR_MSG", ec.message());
1128 // TODO: throw here to force power-control to
1129 // restart?
1130 return;
1131 }
1132 gpiod::line_event line_event = line.event_read();
1133 eventHandler(line_event.event_type ==
1134 gpiod::line_event::RISING_EDGE);
1135 waitForGPIOEvent(name, eventHandler, line, event);
1136 });
Zev Weiss676ef2c2021-09-02 21:54:02 -05001137}
1138
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001139static bool requestGPIOEvents(
Zev Weiss676ef2c2021-09-02 21:54:02 -05001140 const std::string& name, const std::function<void(bool)>& handler,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001141 gpiod::line& gpioLine,
1142 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
1143{
1144 // Find the GPIO line
1145 gpioLine = gpiod::find_line(name);
1146 if (!gpioLine)
1147 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001148 lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001149 return false;
1150 }
1151
1152 try
1153 {
Andrei Kartashev3efcf372021-12-29 15:32:17 +03001154 gpioLine.request({appName, gpiod::line_request::EVENT_BOTH_EDGES, {}});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001155 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001156 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001157 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001158 lg2::error("Failed to request events for {GPIO_NAME}: {ERROR}",
1159 "GPIO_NAME", name, "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001160 return false;
1161 }
1162
1163 int gpioLineFd = gpioLine.event_get_fd();
1164 if (gpioLineFd < 0)
1165 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001166 lg2::error("Failed to get {GPIO_NAME} fd", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001167 return false;
1168 }
1169
1170 gpioEventDescriptor.assign(gpioLineFd);
1171
Zev Weiss676ef2c2021-09-02 21:54:02 -05001172 waitForGPIOEvent(name, handler, gpioLine, gpioEventDescriptor);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001173 return true;
1174}
1175
1176static bool setGPIOOutput(const std::string& name, const int value,
1177 gpiod::line& gpioLine)
1178{
1179 // Find the GPIO line
1180 gpioLine = gpiod::find_line(name);
1181 if (!gpioLine)
1182 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001183 lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001184 return false;
1185 }
1186
1187 // Request GPIO output to specified value
1188 try
1189 {
Andrei Kartashev3efcf372021-12-29 15:32:17 +03001190 gpioLine.request({appName, gpiod::line_request::DIRECTION_OUTPUT, {}},
1191 value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001192 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001193 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001194 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001195 lg2::error("Failed to request {GPIO_NAME} output: {ERROR}", "GPIO_NAME",
1196 name, "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001197 return false;
1198 }
1199
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001200 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1201 "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001202 return true;
1203}
1204
1205static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1206 const std::string& name, const int value,
1207 const int durationMs)
1208{
1209 // Set the masked GPIO line to the specified value
1210 maskedGPIOLine.set_value(value);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001211 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1212 "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001213 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001214 gpioAssertTimer.async_wait(
1215 [maskedGPIOLine, value, name](const boost::system::error_code ec) {
1216 // Set the masked GPIO line back to the opposite value
1217 maskedGPIOLine.set_value(!value);
1218 lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
1219 if (ec)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001220 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001221 // operation_aborted is expected if timer is canceled before
1222 // completion.
1223 if (ec != boost::asio::error::operation_aborted)
1224 {
1225 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1226 "GPIO_NAME", name, "ERROR_MSG", ec.message());
1227 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001228 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001229 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001230 return 0;
1231}
1232
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001233static int setGPIOOutputForMs(const ConfigData& config, const int value,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001234 const int durationMs)
1235{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001236 // If the requested GPIO is masked, use the mask line to set the output
1237 if (powerButtonMask && config.lineName == powerOutConfig.lineName)
1238 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001239 return setMaskedGPIOOutputForMs(powerButtonMask, config.lineName, value,
1240 durationMs);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001241 }
1242 if (resetButtonMask && config.lineName == resetOutConfig.lineName)
1243 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001244 return setMaskedGPIOOutputForMs(resetButtonMask, config.lineName, value,
1245 durationMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001246 }
1247
1248 // No mask set, so request and set the GPIO normally
1249 gpiod::line gpioLine;
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001250 if (!setGPIOOutput(config.lineName, value, gpioLine))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001251 {
1252 return -1;
1253 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001254 const std::string name = config.lineName;
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001255
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001256 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001257 gpioAssertTimer.async_wait(
1258 [gpioLine, value, name](const boost::system::error_code ec) {
1259 // Set the GPIO line back to the opposite value
1260 gpioLine.set_value(!value);
1261 lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
1262 if (ec)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001263 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001264 // operation_aborted is expected if timer is canceled before
1265 // completion.
1266 if (ec != boost::asio::error::operation_aborted)
1267 {
1268 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1269 "GPIO_NAME", name, "ERROR_MSG", ec.message());
1270 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001271 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001272 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001273 return 0;
1274}
1275
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001276static int assertGPIOForMs(const ConfigData& config, const int durationMs)
1277{
1278 return setGPIOOutputForMs(config, config.polarity, durationMs);
1279}
1280
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001281static void powerOn()
1282{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001283 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001284}
Naveen Moses117c34e2021-05-26 20:10:51 +05301285#ifdef CHASSIS_SYSTEM_RESET
1286static int slotPowerOn()
1287{
1288 if (power_control::slotPowerState != power_control::SlotPowerState::on)
1289 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001290
Naveen Moses117c34e2021-05-26 20:10:51 +05301291 slotPowerLine.set_value(1);
1292
1293 if (slotPowerLine.get_value() > 0)
1294 {
1295 setSlotPowerState(SlotPowerState::on);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001296 lg2::info("Slot Power is switched On\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301297 }
1298 else
1299 {
1300 return -1;
1301 }
1302 }
1303 else
1304 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001305 lg2::info("Slot Power is already in 'On' state\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301306 return -1;
1307 }
1308 return 0;
1309}
1310static int slotPowerOff()
1311{
1312 if (power_control::slotPowerState != power_control::SlotPowerState::off)
1313 {
1314 slotPowerLine.set_value(0);
1315
1316 if (!(slotPowerLine.get_value() > 0))
1317 {
1318 setSlotPowerState(SlotPowerState::off);
1319 setPowerState(PowerState::off);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001320 lg2::info("Slot Power is switched Off\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301321 }
1322 else
1323 {
1324 return -1;
1325 }
1326 }
1327 else
1328 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001329 lg2::info("Slot Power is already in 'Off' state\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301330 return -1;
1331 }
1332 return 0;
1333}
1334static void slotPowerCycle()
1335{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001336 lg2::info("Slot Power Cycle started\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301337 slotPowerOff();
1338 slotPowerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001339 std::chrono::milliseconds(TimerMap["SlotPowerCycleMs"]));
Naveen Moses117c34e2021-05-26 20:10:51 +05301340 slotPowerCycleTimer.async_wait([](const boost::system::error_code ec) {
1341 if (ec)
1342 {
1343 if (ec != boost::asio::error::operation_aborted)
1344 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001345 lg2::error(
1346 "Slot Power cycle timer async_wait failed: {ERROR_MSG}",
1347 "ERROR_MSG", ec.message());
Naveen Moses117c34e2021-05-26 20:10:51 +05301348 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001349 lg2::info("Slot Power cycle timer canceled\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301350 return;
1351 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001352 lg2::info("Slot Power cycle timer completed\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301353 slotPowerOn();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001354 lg2::info("Slot Power Cycle Completed\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301355 });
1356}
1357#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001358static void gracefulPowerOff()
1359{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001360 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001361}
1362
1363static void forcePowerOff()
1364{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001365 if (assertGPIOForMs(powerOutConfig, TimerMap["ForceOffPulseMs"]) < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001366 {
1367 return;
1368 }
1369
Jason M. Billsc6961b62021-10-21 14:08:02 -07001370 // If the force off timer expires, then the power-button override failed
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001371 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1372 if (ec)
1373 {
1374 // operation_aborted is expected if timer is canceled before
1375 // completion.
1376 if (ec != boost::asio::error::operation_aborted)
1377 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001378 lg2::error("Force power off async_wait failed: {ERROR_MSG}",
1379 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001380 }
1381 return;
1382 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001383
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001384 lg2::error("Power-button override failed. Not sure what to do now.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001385 });
1386}
1387
1388static void reset()
1389{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001390 assertGPIOForMs(resetOutConfig, TimerMap["ResetPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001391}
1392
1393static void gracefulPowerOffTimerStart()
1394{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001395 lg2::info("Graceful power-off timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001396 gracefulPowerOffTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001397 std::chrono::seconds(TimerMap["GracefulPowerOffS"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001398 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1399 if (ec)
1400 {
1401 // operation_aborted is expected if timer is canceled before
1402 // completion.
1403 if (ec != boost::asio::error::operation_aborted)
1404 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001405 lg2::error("Graceful power-off async_wait failed: {ERROR_MSG}",
1406 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001407 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001408 lg2::info("Graceful power-off timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001409 return;
1410 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001411 lg2::info("Graceful power-off timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001412 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1413 });
1414}
1415
1416static void powerCycleTimerStart()
1417{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001418 lg2::info("Power-cycle timer started");
Priyatharshan P70120512020-09-16 18:47:20 +05301419 powerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001420 std::chrono::milliseconds(TimerMap["PowerCycleMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001421 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1422 if (ec)
1423 {
1424 // operation_aborted is expected if timer is canceled before
1425 // completion.
1426 if (ec != boost::asio::error::operation_aborted)
1427 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001428 lg2::error("Power-cycle async_wait failed: {ERROR_MSG}",
1429 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001430 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001431 lg2::info("Power-cycle timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001432 return;
1433 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001434 lg2::info("Power-cycle timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001435 sendPowerControlEvent(Event::powerCycleTimerExpired);
1436 });
1437}
1438
1439static void psPowerOKWatchdogTimerStart()
1440{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001441 lg2::info("power supply power OK watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001442 psPowerOKWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001443 std::chrono::milliseconds(TimerMap["PsPowerOKWatchdogMs"]));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001444 psPowerOKWatchdogTimer.async_wait([](const boost::system::error_code ec) {
1445 if (ec)
1446 {
1447 // operation_aborted is expected if timer is canceled before
1448 // completion.
1449 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001450 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001451 lg2::error(
1452 "power supply power OK watchdog async_wait failed: {ERROR_MSG}",
1453 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001454 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001455 lg2::info("power supply power OK watchdog timer canceled");
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001456 return;
1457 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001458 lg2::info("power supply power OK watchdog timer expired");
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001459 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1460 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001461}
1462
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001463static void warmResetCheckTimerStart()
1464{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001465 lg2::info("Warm reset check timer started");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001466 warmResetCheckTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001467 std::chrono::milliseconds(TimerMap["WarmResetCheckMs"]));
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001468 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1469 if (ec)
1470 {
1471 // operation_aborted is expected if timer is canceled before
1472 // completion.
1473 if (ec != boost::asio::error::operation_aborted)
1474 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001475 lg2::error("Warm reset check async_wait failed: {ERROR_MSG}",
1476 "ERROR_MSG", ec.message());
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001477 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001478 lg2::info("Warm reset check timer canceled");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001479 return;
1480 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001481 lg2::info("Warm reset check timer completed");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001482 sendPowerControlEvent(Event::warmResetDetected);
1483 });
1484}
1485
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001486static void pohCounterTimerStart()
1487{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001488 lg2::info("POH timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001489 // Set the time-out as 1 hour, to align with POH command in ipmid
1490 pohCounterTimer.expires_after(std::chrono::hours(1));
1491 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1492 if (ec)
1493 {
1494 // operation_aborted is expected if timer is canceled before
1495 // completion.
1496 if (ec != boost::asio::error::operation_aborted)
1497 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001498 lg2::error("POH timer async_wait failed: {ERROR_MSG}",
1499 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001500 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001501 lg2::info("POH timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001502 return;
1503 }
1504
1505 if (getHostState(powerState) !=
1506 "xyz.openbmc_project.State.Host.HostState.Running")
1507 {
1508 return;
1509 }
1510
1511 conn->async_method_call(
1512 [](boost::system::error_code ec,
1513 const std::variant<uint32_t>& pohCounterProperty) {
1514 if (ec)
1515 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001516 lg2::error("error getting poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001517 return;
1518 }
1519 const uint32_t* pohCounter =
1520 std::get_if<uint32_t>(&pohCounterProperty);
1521 if (pohCounter == nullptr)
1522 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001523 lg2::error("unable to read poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001524 return;
1525 }
1526
1527 conn->async_method_call(
1528 [](boost::system::error_code ec) {
1529 if (ec)
1530 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001531 lg2::error("failed to set poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001532 }
1533 },
1534 "xyz.openbmc_project.Settings",
1535 "/xyz/openbmc_project/state/chassis0",
1536 "org.freedesktop.DBus.Properties", "Set",
1537 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1538 std::variant<uint32_t>(*pohCounter + 1));
1539 },
1540 "xyz.openbmc_project.Settings",
1541 "/xyz/openbmc_project/state/chassis0",
1542 "org.freedesktop.DBus.Properties", "Get",
1543 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1544
1545 pohCounterTimerStart();
1546 });
1547}
1548
1549static void currentHostStateMonitor()
1550{
Yong Li8d660212019-12-27 10:18:10 +08001551 if (getHostState(powerState) ==
1552 "xyz.openbmc_project.State.Host.HostState.Running")
1553 {
1554 pohCounterTimerStart();
1555 // Clear the restart cause set for the next restart
1556 clearRestartCause();
1557 }
1558 else
1559 {
1560 pohCounterTimer.cancel();
1561 // Set the restart cause set for this restart
1562 setRestartCause();
1563 }
1564
Patrick Williams439b9c32022-07-22 19:26:53 -05001565 static auto match = sdbusplus::bus::match_t(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001566 *conn,
1567 "type='signal',member='PropertiesChanged', "
1568 "interface='org.freedesktop.DBus.Properties', "
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001569 "arg0='xyz.openbmc_project.State.Host'",
Patrick Williams439b9c32022-07-22 19:26:53 -05001570 [](sdbusplus::message_t& message) {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001571 std::string intfName;
1572 std::map<std::string, std::variant<std::string>> properties;
1573
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001574 try
1575 {
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001576 message.read(intfName, properties);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001577 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05001578 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001579 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001580 lg2::error("Unable to read host state: {ERROR}", "ERROR", e);
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001581 return;
1582 }
1583 if (properties.empty())
1584 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001585 lg2::error("ERROR: Empty PropertiesChanged signal received");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001586 return;
1587 }
1588
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001589 // We only want to check for CurrentHostState
1590 if (properties.begin()->first != "CurrentHostState")
1591 {
1592 return;
1593 }
1594 std::string* currentHostState =
1595 std::get_if<std::string>(&(properties.begin()->second));
1596 if (currentHostState == nullptr)
1597 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001598 lg2::error("{PROPERTY} property invalid", "PROPERTY",
1599 properties.begin()->first);
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001600 return;
1601 }
1602
1603 if (*currentHostState ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001604 "xyz.openbmc_project.State.Host.HostState.Running")
1605 {
1606 pohCounterTimerStart();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001607 // Clear the restart cause set for the next restart
1608 clearRestartCause();
Yong Li8d660212019-12-27 10:18:10 +08001609 sd_journal_send("MESSAGE=Host system DC power is on",
1610 "PRIORITY=%i", LOG_INFO,
1611 "REDFISH_MESSAGE_ID=%s",
1612 "OpenBMC.0.1.DCPowerOn", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001613 }
1614 else
1615 {
1616 pohCounterTimer.cancel();
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301617 // POST_COMPLETE GPIO event is not working in some platforms
1618 // when power state is changed to OFF. This resulted in
1619 // 'OperatingSystemState' to stay at 'Standby', even though
1620 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1621 // if HostState is trurned to OFF.
Tim Lee86239182021-12-23 11:46:01 +08001622 setOperatingSystemState(OperatingSystemStateStage::Inactive);
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301623
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001624 // Set the restart cause set for this restart
1625 setRestartCause();
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001626#ifdef USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +05301627 resetACBootProperty();
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001628#endif // USE_ACBOOT
Yong Li8d660212019-12-27 10:18:10 +08001629 sd_journal_send("MESSAGE=Host system DC power is off",
1630 "PRIORITY=%i", LOG_INFO,
1631 "REDFISH_MESSAGE_ID=%s",
1632 "OpenBMC.0.1.DCPowerOff", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001633 }
1634 });
1635}
1636
1637static void sioPowerGoodWatchdogTimerStart()
1638{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001639 lg2::info("SIO power good watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001640 sioPowerGoodWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001641 std::chrono::milliseconds(TimerMap["SioPowerGoodWatchdogMs"]));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001642 sioPowerGoodWatchdogTimer.async_wait([](const boost::system::error_code
1643 ec) {
1644 if (ec)
1645 {
1646 // operation_aborted is expected if timer is canceled before
1647 // completion.
1648 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001649 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001650 lg2::error(
1651 "SIO power good watchdog async_wait failed: {ERROR_MSG}",
1652 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001653 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001654 lg2::info("SIO power good watchdog timer canceled");
1655 return;
1656 }
1657 lg2::info("SIO power good watchdog timer completed");
1658 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1659 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001660}
1661
1662static void powerStateOn(const Event event)
1663{
1664 logEvent(__FUNCTION__, event);
1665 switch (event)
1666 {
1667 case Event::psPowerOKDeAssert:
1668 setPowerState(PowerState::off);
1669 // DC power is unexpectedly lost, beep
1670 beep(beepPowerFail);
1671 break;
1672 case Event::sioS5Assert:
1673 setPowerState(PowerState::transitionToOff);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001674 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001675 break;
Jason M. Billsfb957332021-01-28 13:18:46 -08001676#if USE_PLT_RST
1677 case Event::pltRstAssert:
1678#else
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001679 case Event::postCompleteDeAssert:
Jason M. Billsfb957332021-01-28 13:18:46 -08001680#endif
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001681 setPowerState(PowerState::checkForWarmReset);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001682 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001683 warmResetCheckTimerStart();
1684 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001685 case Event::powerButtonPressed:
1686 setPowerState(PowerState::gracefulTransitionToOff);
1687 gracefulPowerOffTimerStart();
1688 break;
1689 case Event::powerOffRequest:
1690 setPowerState(PowerState::transitionToOff);
1691 forcePowerOff();
1692 break;
1693 case Event::gracefulPowerOffRequest:
1694 setPowerState(PowerState::gracefulTransitionToOff);
1695 gracefulPowerOffTimerStart();
1696 gracefulPowerOff();
1697 break;
1698 case Event::powerCycleRequest:
1699 setPowerState(PowerState::transitionToCycleOff);
1700 forcePowerOff();
1701 break;
1702 case Event::gracefulPowerCycleRequest:
1703 setPowerState(PowerState::gracefulTransitionToCycleOff);
1704 gracefulPowerOffTimerStart();
1705 gracefulPowerOff();
1706 break;
1707 case Event::resetRequest:
1708 reset();
1709 break;
1710 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001711 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001712 break;
1713 }
1714}
1715
1716static void powerStateWaitForPSPowerOK(const Event event)
1717{
1718 logEvent(__FUNCTION__, event);
1719 switch (event)
1720 {
1721 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301722 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001723 // Cancel any GPIO assertions held during the transition
1724 gpioAssertTimer.cancel();
1725 psPowerOKWatchdogTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301726 if (sioEnabled == true)
1727 {
1728 sioPowerGoodWatchdogTimerStart();
1729 setPowerState(PowerState::waitForSIOPowerGood);
1730 }
1731 else
1732 {
1733 setPowerState(PowerState::on);
1734 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001735 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301736 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001737 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001738 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001739 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001740 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001741 case Event::sioPowerGoodAssert:
1742 psPowerOKWatchdogTimer.cancel();
1743 setPowerState(PowerState::on);
1744 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001745 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001746 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001747 break;
1748 }
1749}
1750
1751static void powerStateWaitForSIOPowerGood(const Event event)
1752{
1753 logEvent(__FUNCTION__, event);
1754 switch (event)
1755 {
1756 case Event::sioPowerGoodAssert:
1757 sioPowerGoodWatchdogTimer.cancel();
1758 setPowerState(PowerState::on);
1759 break;
1760 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001761 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001762 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001763 break;
1764 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001765 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001766 break;
1767 }
1768}
1769
1770static void powerStateOff(const Event event)
1771{
1772 logEvent(__FUNCTION__, event);
1773 switch (event)
1774 {
1775 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301776 {
1777 if (sioEnabled == true)
1778 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001779 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301780 setPowerState(PowerState::waitForSIOPowerGood);
1781 }
1782 else
1783 {
1784 setPowerState(PowerState::on);
1785 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001786 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301787 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001788 case Event::sioS5DeAssert:
Jason M. Billsfe159032022-09-01 16:03:37 -07001789 psPowerOKWatchdogTimerStart();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001790 setPowerState(PowerState::waitForPSPowerOK);
1791 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001792 case Event::sioPowerGoodAssert:
1793 setPowerState(PowerState::on);
1794 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001795 case Event::powerButtonPressed:
1796 psPowerOKWatchdogTimerStart();
1797 setPowerState(PowerState::waitForPSPowerOK);
1798 break;
1799 case Event::powerOnRequest:
1800 psPowerOKWatchdogTimerStart();
1801 setPowerState(PowerState::waitForPSPowerOK);
1802 powerOn();
1803 break;
1804 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001805 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001806 break;
1807 }
1808}
1809
1810static void powerStateTransitionToOff(const Event event)
1811{
1812 logEvent(__FUNCTION__, event);
1813 switch (event)
1814 {
1815 case Event::psPowerOKDeAssert:
1816 // Cancel any GPIO assertions held during the transition
1817 gpioAssertTimer.cancel();
1818 setPowerState(PowerState::off);
1819 break;
1820 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001821 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001822 break;
1823 }
1824}
1825
1826static void powerStateGracefulTransitionToOff(const Event event)
1827{
1828 logEvent(__FUNCTION__, event);
1829 switch (event)
1830 {
1831 case Event::psPowerOKDeAssert:
1832 gracefulPowerOffTimer.cancel();
1833 setPowerState(PowerState::off);
1834 break;
1835 case Event::gracefulPowerOffTimerExpired:
1836 setPowerState(PowerState::on);
1837 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001838 case Event::powerOffRequest:
1839 gracefulPowerOffTimer.cancel();
1840 setPowerState(PowerState::transitionToOff);
1841 forcePowerOff();
1842 break;
1843 case Event::powerCycleRequest:
1844 gracefulPowerOffTimer.cancel();
1845 setPowerState(PowerState::transitionToCycleOff);
1846 forcePowerOff();
1847 break;
1848 case Event::resetRequest:
1849 gracefulPowerOffTimer.cancel();
1850 setPowerState(PowerState::on);
1851 reset();
1852 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001853 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001854 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001855 break;
1856 }
1857}
1858
1859static void powerStateCycleOff(const Event event)
1860{
1861 logEvent(__FUNCTION__, event);
1862 switch (event)
1863 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001864 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301865 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001866 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301867 if (sioEnabled == true)
1868 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001869 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301870 setPowerState(PowerState::waitForSIOPowerGood);
1871 }
1872 else
1873 {
1874 setPowerState(PowerState::on);
1875 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001876 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301877 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001878 case Event::sioS5DeAssert:
1879 powerCycleTimer.cancel();
Jason M. Billsfe159032022-09-01 16:03:37 -07001880 psPowerOKWatchdogTimerStart();
Jason M. Bills35aa6652020-04-30 16:24:55 -07001881 setPowerState(PowerState::waitForPSPowerOK);
1882 break;
1883 case Event::powerButtonPressed:
1884 powerCycleTimer.cancel();
1885 psPowerOKWatchdogTimerStart();
1886 setPowerState(PowerState::waitForPSPowerOK);
1887 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001888 case Event::powerCycleTimerExpired:
1889 psPowerOKWatchdogTimerStart();
1890 setPowerState(PowerState::waitForPSPowerOK);
1891 powerOn();
1892 break;
1893 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001894 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001895 break;
1896 }
1897}
1898
1899static void powerStateTransitionToCycleOff(const Event event)
1900{
1901 logEvent(__FUNCTION__, event);
1902 switch (event)
1903 {
1904 case Event::psPowerOKDeAssert:
1905 // Cancel any GPIO assertions held during the transition
1906 gpioAssertTimer.cancel();
1907 setPowerState(PowerState::cycleOff);
1908 powerCycleTimerStart();
1909 break;
1910 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001911 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001912 break;
1913 }
1914}
1915
1916static void powerStateGracefulTransitionToCycleOff(const Event event)
1917{
1918 logEvent(__FUNCTION__, event);
1919 switch (event)
1920 {
1921 case Event::psPowerOKDeAssert:
1922 gracefulPowerOffTimer.cancel();
1923 setPowerState(PowerState::cycleOff);
1924 powerCycleTimerStart();
1925 break;
1926 case Event::gracefulPowerOffTimerExpired:
1927 setPowerState(PowerState::on);
1928 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001929 case Event::powerOffRequest:
1930 gracefulPowerOffTimer.cancel();
1931 setPowerState(PowerState::transitionToOff);
1932 forcePowerOff();
1933 break;
1934 case Event::powerCycleRequest:
1935 gracefulPowerOffTimer.cancel();
1936 setPowerState(PowerState::transitionToCycleOff);
1937 forcePowerOff();
1938 break;
1939 case Event::resetRequest:
1940 gracefulPowerOffTimer.cancel();
1941 setPowerState(PowerState::on);
1942 reset();
1943 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001944 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001945 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001946 break;
1947 }
1948}
1949
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001950static void powerStateCheckForWarmReset(const Event event)
1951{
1952 logEvent(__FUNCTION__, event);
1953 switch (event)
1954 {
1955 case Event::sioS5Assert:
1956 warmResetCheckTimer.cancel();
1957 setPowerState(PowerState::transitionToOff);
1958 break;
1959 case Event::warmResetDetected:
1960 setPowerState(PowerState::on);
1961 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001962 case Event::psPowerOKDeAssert:
1963 warmResetCheckTimer.cancel();
1964 setPowerState(PowerState::off);
1965 // DC power is unexpectedly lost, beep
1966 beep(beepPowerFail);
1967 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001968 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001969 lg2::info("No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001970 break;
1971 }
1972}
1973
Zev Weiss584aa132021-09-02 19:21:52 -05001974static void psPowerOKHandler(bool state)
1975{
1976 Event powerControlEvent =
1977 state ? Event::psPowerOKAssert : Event::psPowerOKDeAssert;
1978 sendPowerControlEvent(powerControlEvent);
1979}
1980
Zev Weiss584aa132021-09-02 19:21:52 -05001981static void sioPowerGoodHandler(bool state)
1982{
1983 Event powerControlEvent =
1984 state ? Event::sioPowerGoodAssert : Event::sioPowerGoodDeAssert;
1985 sendPowerControlEvent(powerControlEvent);
1986}
1987
Zev Weiss584aa132021-09-02 19:21:52 -05001988static void sioOnControlHandler(bool state)
1989{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001990 lg2::info("SIO_ONCONTROL value changed: {VALUE}", "VALUE",
1991 static_cast<int>(state));
Zev Weiss584aa132021-09-02 19:21:52 -05001992}
1993
Zev Weiss584aa132021-09-02 19:21:52 -05001994static void sioS5Handler(bool state)
1995{
1996 Event powerControlEvent = state ? Event::sioS5DeAssert : Event::sioS5Assert;
1997 sendPowerControlEvent(powerControlEvent);
1998}
1999
Zev Weiss584aa132021-09-02 19:21:52 -05002000static void powerButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002001{
Zev Weiss584aa132021-09-02 19:21:52 -05002002 powerButtonIface->set_property("ButtonPressed", !state);
2003 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002004 {
2005 powerButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002006 if (!powerButtonMask)
2007 {
2008 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002009 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002010 }
2011 else
2012 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002013 lg2::info("power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002014 }
2015 }
Zev Weiss584aa132021-09-02 19:21:52 -05002016}
2017
Zev Weiss584aa132021-09-02 19:21:52 -05002018static void resetButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002019{
Zev Weiss584aa132021-09-02 19:21:52 -05002020 resetButtonIface->set_property("ButtonPressed", !state);
2021 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002022 {
2023 resetButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002024 if (!resetButtonMask)
2025 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002026 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002027 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002028 }
2029 else
2030 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002031 lg2::info("reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002032 }
2033 }
Zev Weiss584aa132021-09-02 19:21:52 -05002034}
2035
Vijay Khemka04175c22020-10-09 14:28:11 -07002036#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002037static constexpr auto systemdBusname = "org.freedesktop.systemd1";
2038static constexpr auto systemdPath = "/org/freedesktop/systemd1";
2039static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
2040static constexpr auto systemTargetName = "chassis-system-reset.target";
2041
2042void systemReset()
2043{
2044 conn->async_method_call(
2045 [](boost::system::error_code ec) {
2046 if (ec)
2047 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002048 lg2::error("Failed to call chassis system reset: {ERR}", "ERR",
2049 ec.message());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002050 }
2051 },
2052 systemdBusname, systemdPath, systemdInterface, "StartUnit",
2053 systemTargetName, "replace");
2054}
Vijay Khemka04175c22020-10-09 14:28:11 -07002055#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002056
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002057static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002058{
2059 conn->async_method_call(
2060 [](boost::system::error_code ec) {
2061 if (ec)
2062 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002063 lg2::error("failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002064 }
2065 },
Chen Yugang303bd582019-11-01 08:45:06 +08002066 "xyz.openbmc_project.Settings",
2067 "/xyz/openbmc_project/Chassis/Control/NMISource",
2068 "org.freedesktop.DBus.Properties", "Set",
2069 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
2070 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002071}
2072
2073static void nmiReset(void)
2074{
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002075 const static constexpr int nmiOutPulseTimeMs = 200;
2076
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002077 lg2::info("NMI out action");
Ping Guo8643c792022-05-18 08:32:00 +08002078 nmiOutLine.set_value(!nmiOutConfig.polarity);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002079 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME",
Ping Guo8643c792022-05-18 08:32:00 +08002080 nmiOutConfig.lineName, "GPIO_VALUE", !nmiOutConfig.polarity);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002081 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2082 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2083 // restore the NMI_OUT GPIO line back to the opposite value
Ping Guo8643c792022-05-18 08:32:00 +08002084 nmiOutLine.set_value(nmiOutConfig.polarity);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002085 lg2::info("{GPIO_NAME} released", "GPIO_NAME", nmiOutConfig.lineName);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002086 if (ec)
2087 {
2088 // operation_aborted is expected if timer is canceled before
2089 // completion.
2090 if (ec != boost::asio::error::operation_aborted)
2091 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002092 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
2093 "GPIO_NAME", nmiOutConfig.lineName, "ERROR_MSG",
2094 ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002095 }
2096 }
2097 });
2098 // log to redfish
2099 nmiDiagIntLog();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002100 lg2::info("NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002101 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002102 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002103}
2104
2105static void nmiSourcePropertyMonitor(void)
2106{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002107 lg2::info("NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002108
Patrick Williams439b9c32022-07-22 19:26:53 -05002109 static std::unique_ptr<sdbusplus::bus::match_t> nmiSourceMatch =
2110 std::make_unique<sdbusplus::bus::match_t>(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002111 *conn,
2112 "type='signal',interface='org.freedesktop.DBus.Properties',"
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002113 "member='PropertiesChanged',"
2114 "arg0namespace='xyz.openbmc_project.Chassis.Control.NMISource'",
Patrick Williams439b9c32022-07-22 19:26:53 -05002115 [](sdbusplus::message_t& msg) {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002116 std::string interfaceName;
2117 boost::container::flat_map<std::string,
2118 std::variant<bool, std::string>>
2119 propertiesChanged;
2120 std::string state;
2121 bool value = true;
2122 try
2123 {
2124 msg.read(interfaceName, propertiesChanged);
2125 if (propertiesChanged.begin()->first == "Enabled")
2126 {
2127 value =
2128 std::get<bool>(propertiesChanged.begin()->second);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002129 lg2::info(
2130 "NMI Enabled propertiesChanged value: {VALUE}",
2131 "VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002132 nmiEnabled = value;
2133 if (nmiEnabled)
2134 {
2135 nmiReset();
2136 }
2137 }
2138 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002139 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002140 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002141 lg2::error("Unable to read NMI source: {ERROR}", "ERROR",
2142 e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002143 return;
2144 }
2145 });
2146}
2147
2148static void setNmiSource()
2149{
2150 conn->async_method_call(
2151 [](boost::system::error_code ec) {
2152 if (ec)
2153 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002154 lg2::error("failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002155 }
2156 },
Chen Yugang303bd582019-11-01 08:45:06 +08002157 "xyz.openbmc_project.Settings",
2158 "/xyz/openbmc_project/Chassis/Control/NMISource",
2159 "org.freedesktop.DBus.Properties", "Set",
2160 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
Jason M. Bills418ce112021-09-08 15:15:05 -07002161 std::variant<std::string>{
2162 "xyz.openbmc_project.Chassis.Control.NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002163 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002164 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002165}
2166
Zev Weiss584aa132021-09-02 19:21:52 -05002167static void nmiButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002168{
Zev Weiss584aa132021-09-02 19:21:52 -05002169 nmiButtonIface->set_property("ButtonPressed", !state);
2170 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002171 {
2172 nmiButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002173 if (nmiButtonMasked)
2174 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002175 lg2::info("NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002176 }
2177 else
2178 {
2179 setNmiSource();
2180 }
2181 }
Zev Weiss584aa132021-09-02 19:21:52 -05002182}
2183
Zev Weiss584aa132021-09-02 19:21:52 -05002184static void idButtonHandler(bool state)
2185{
2186 idButtonIface->set_property("ButtonPressed", !state);
2187}
2188
Jason M. Billsfb957332021-01-28 13:18:46 -08002189static void pltRstHandler(bool pltRst)
2190{
2191 if (pltRst)
2192 {
2193 sendPowerControlEvent(Event::pltRstDeAssert);
2194 }
2195 else
2196 {
2197 sendPowerControlEvent(Event::pltRstAssert);
2198 }
2199}
2200
Patrick Williams439b9c32022-07-22 19:26:53 -05002201[[maybe_unused]] static void hostMiscHandler(sdbusplus::message_t& msg)
Jason M. Billsfb957332021-01-28 13:18:46 -08002202{
2203 std::string interfaceName;
2204 boost::container::flat_map<std::string, std::variant<bool>>
2205 propertiesChanged;
Jason M. Billsfb957332021-01-28 13:18:46 -08002206 try
2207 {
2208 msg.read(interfaceName, propertiesChanged);
2209 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002210 catch (const std::exception& e)
Jason M. Billsfb957332021-01-28 13:18:46 -08002211 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002212 lg2::error("Unable to read Host Misc status: {ERROR}", "ERROR", e);
Jason M. Billsfb957332021-01-28 13:18:46 -08002213 return;
2214 }
2215 if (propertiesChanged.empty())
2216 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002217 lg2::error("ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002218 return;
2219 }
2220
2221 for (auto& [property, value] : propertiesChanged)
2222 {
2223 if (property == "ESpiPlatformReset")
2224 {
2225 bool* pltRst = std::get_if<bool>(&value);
2226 if (pltRst == nullptr)
2227 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002228 lg2::error("{PROPERTY} property invalid", "PROPERTY", property);
Jason M. Billsfb957332021-01-28 13:18:46 -08002229 return;
2230 }
2231 pltRstHandler(*pltRst);
2232 }
2233 }
2234}
2235
Zev Weiss584aa132021-09-02 19:21:52 -05002236static void postCompleteHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002237{
Zev Weiss584aa132021-09-02 19:21:52 -05002238 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002239 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002240 sendPowerControlEvent(Event::postCompleteAssert);
Tim Lee86239182021-12-23 11:46:01 +08002241 setOperatingSystemState(OperatingSystemStateStage::Standby);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002242 }
2243 else
2244 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002245 sendPowerControlEvent(Event::postCompleteDeAssert);
Tim Lee86239182021-12-23 11:46:01 +08002246 setOperatingSystemState(OperatingSystemStateStage::Inactive);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002247 }
Zev Weiss584aa132021-09-02 19:21:52 -05002248}
2249
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302250static int loadConfigValues()
2251{
2252 const std::string configFilePath =
2253 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2254 ".json";
2255 std::ifstream configFile(configFilePath.c_str());
2256 if (!configFile.is_open())
2257 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002258 lg2::error("loadConfigValues: Cannot open config path \'{PATH}\'",
2259 "PATH", configFilePath);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302260 return -1;
2261 }
Zev Weiss1aa08b22021-09-15 17:06:20 -05002262 auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302263
Priyatharshan P70120512020-09-16 18:47:20 +05302264 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302265 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002266 lg2::error("Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302267 return -1;
2268 }
Priyatharshan P70120512020-09-16 18:47:20 +05302269 auto gpios = jsonData["gpio_configs"];
2270 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302271
Priyatharshan P70120512020-09-16 18:47:20 +05302272 ConfigData* tempGpioData;
2273
2274 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302275 {
Priyatharshan P70120512020-09-16 18:47:20 +05302276 if (!gpioConfig.contains("Name"))
2277 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002278 lg2::error("The 'Name' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302279 return -1;
2280 }
2281
2282 // Iterate through the powersignal map to check if the gpio json config
2283 // entry is valid
2284 std::string gpioName = gpioConfig["Name"];
2285 auto signalMapIter = powerSignalMap.find(gpioName);
2286 if (signalMapIter == powerSignalMap.end())
2287 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002288 lg2::error(
2289 "{GPIO_NAME} is not a recognized power-control signal name",
2290 "GPIO_NAME", gpioName);
Priyatharshan P70120512020-09-16 18:47:20 +05302291 return -1;
2292 }
2293
2294 // assign the power signal name to the corresponding structure reference
2295 // from map then fillup the structure with coressponding json config
2296 // value
2297 tempGpioData = signalMapIter->second;
2298 tempGpioData->name = gpioName;
2299
2300 if (!gpioConfig.contains("Type"))
2301 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002302 lg2::error("The \'Type\' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302303 return -1;
2304 }
2305
2306 std::string signalType = gpioConfig["Type"];
2307 if (signalType == "GPIO")
2308 {
2309 tempGpioData->type = ConfigType::GPIO;
2310 }
2311 else if (signalType == "DBUS")
2312 {
2313 tempGpioData->type = ConfigType::DBUS;
2314 }
2315 else
2316 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002317 lg2::error("{TYPE} is not a recognized power-control signal type",
2318 "TYPE", signalType);
Priyatharshan P70120512020-09-16 18:47:20 +05302319 return -1;
2320 }
2321
2322 if (tempGpioData->type == ConfigType::GPIO)
2323 {
2324 if (gpioConfig.contains("LineName"))
2325 {
2326 tempGpioData->lineName = gpioConfig["LineName"];
2327 }
2328 else
2329 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002330 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002331 "The \'LineName\' field must be defined for GPIO configuration");
Priyatharshan P70120512020-09-16 18:47:20 +05302332 return -1;
2333 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002334 if (gpioConfig.contains("Polarity"))
2335 {
2336 std::string polarity = gpioConfig["Polarity"];
2337 if (polarity == "ActiveLow")
2338 {
2339 tempGpioData->polarity = false;
2340 }
2341 else if (polarity == "ActiveHigh")
2342 {
2343 tempGpioData->polarity = true;
2344 }
2345 else
2346 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002347 lg2::error(
2348 "Polarity defined but not properly setup. Please only ActiveHigh or ActiveLow. Currently set to {POLARITY}",
2349 "POLARITY", polarity);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002350 return -1;
2351 }
2352 }
2353 else
2354 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002355 lg2::error("Polarity field not found for {GPIO_NAME}",
2356 "GPIO_NAME", tempGpioData->lineName);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002357 return -1;
2358 }
Priyatharshan P70120512020-09-16 18:47:20 +05302359 }
2360 else
2361 {
2362 // if dbus based gpio config is defined read and update the dbus
2363 // params corresponding to the gpio config instance
2364 for (auto& [key, dbusParamName] : dbusParams)
2365 {
Logananth Sundararaja4308042021-10-20 11:52:05 +05302366 if (!gpioConfig.contains(dbusParamName))
Priyatharshan P70120512020-09-16 18:47:20 +05302367 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002368 lg2::error(
2369 "The {DBUS_NAME} field must be defined for Dbus configuration ",
2370 "DBUS_NAME", dbusParamName);
Priyatharshan P70120512020-09-16 18:47:20 +05302371 return -1;
2372 }
2373 }
Logananth Sundararaja4308042021-10-20 11:52:05 +05302374 tempGpioData->dbusName =
2375 gpioConfig[dbusParams[DbusConfigType::name]];
2376 tempGpioData->path = gpioConfig[dbusParams[DbusConfigType::path]];
Priyatharshan P70120512020-09-16 18:47:20 +05302377 tempGpioData->interface =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302378 gpioConfig[dbusParams[DbusConfigType::interface]];
Priyatharshan P70120512020-09-16 18:47:20 +05302379 tempGpioData->lineName =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302380 gpioConfig[dbusParams[DbusConfigType::property]];
Priyatharshan P70120512020-09-16 18:47:20 +05302381 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302382 }
2383
Priyatharshan P70120512020-09-16 18:47:20 +05302384 // read and store the timer values from json config to Timer Map
2385 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302386 {
Priyatharshan P70120512020-09-16 18:47:20 +05302387 if (timers.contains(key.c_str()))
2388 {
2389 timerValue = timers[key.c_str()];
2390 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302391 }
2392
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302393 return 0;
2394}
Zev Weissa8f116a2021-09-01 21:08:30 -05002395
Patrick Williams439b9c32022-07-22 19:26:53 -05002396static bool getDbusMsgGPIOState(sdbusplus::message_t& msg,
Zev Weissa8f116a2021-09-01 21:08:30 -05002397 const std::string& lineName, bool& value)
2398{
2399 std::string thresholdInterface;
2400 std::string event;
2401 boost::container::flat_map<std::string, std::variant<bool>>
2402 propertiesChanged;
2403 try
2404 {
2405 msg.read(thresholdInterface, propertiesChanged);
2406 if (propertiesChanged.empty())
2407 {
2408 return false;
2409 }
2410
2411 event = propertiesChanged.begin()->first;
2412 if (event.empty() || event != lineName)
2413 {
2414 return false;
2415 }
2416
2417 value = std::get<bool>(propertiesChanged.begin()->second);
2418 return true;
2419 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002420 catch (const std::exception& e)
Zev Weissa8f116a2021-09-01 21:08:30 -05002421 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002422 lg2::error(
2423 "exception while reading dbus property \'{DBUS_NAME}\': {ERROR}",
2424 "DBUS_NAME", lineName, "ERROR", e);
Zev Weissa8f116a2021-09-01 21:08:30 -05002425 return false;
2426 }
2427}
2428
Patrick Williams439b9c32022-07-22 19:26:53 -05002429static sdbusplus::bus::match_t
Zev Weissa8f116a2021-09-01 21:08:30 -05002430 dbusGPIOMatcher(const ConfigData& cfg, std::function<void(bool)> onMatch)
2431{
Patrick Williams439b9c32022-07-22 19:26:53 -05002432 auto pulseEventMatcherCallback = [&cfg,
2433 onMatch](sdbusplus::message_t& msg) {
2434 bool value = false;
2435 if (!getDbusMsgGPIOState(msg, cfg.lineName, value))
2436 {
2437 return;
2438 }
2439 onMatch(value);
2440 };
Zev Weissa8f116a2021-09-01 21:08:30 -05002441
Patrick Williams439b9c32022-07-22 19:26:53 -05002442 return sdbusplus::bus::match_t(
2443 static_cast<sdbusplus::bus_t&>(*conn),
Zev Weissa8f116a2021-09-01 21:08:30 -05002444 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2445 "PropertiesChanged',arg0='" +
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302446 cfg.interface + "'",
Zev Weissa8f116a2021-09-01 21:08:30 -05002447 std::move(pulseEventMatcherCallback));
2448}
2449
Priyatharshan P70120512020-09-16 18:47:20 +05302450int getProperty(ConfigData& configData)
2451{
2452 auto method = conn->new_method_call(
2453 configData.dbusName.c_str(), configData.path.c_str(),
2454 "org.freedesktop.DBus.Properties", "Get");
2455 method.append(configData.interface.c_str(), configData.lineName.c_str());
2456
2457 auto reply = conn->call(method);
2458 if (reply.is_method_error())
2459 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002460 lg2::error(
2461 "Error reading {PROPERTY} D-Bus property on interface {INTERFACE} and path {PATH}",
2462 "PROPERTY", configData.lineName, "INTERFACE", configData.interface,
2463 "PATH", configData.path);
Priyatharshan P70120512020-09-16 18:47:20 +05302464 return -1;
2465 }
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302466 std::variant<bool> resp;
Priyatharshan P70120512020-09-16 18:47:20 +05302467 reply.read(resp);
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302468 auto respValue = std::get_if<bool>(&resp);
Priyatharshan P70120512020-09-16 18:47:20 +05302469 if (!respValue)
2470 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002471 lg2::error("Error: {PROPERTY} D-Bus property is not the expected type",
2472 "PROPERTY", configData.lineName);
Priyatharshan P70120512020-09-16 18:47:20 +05302473 return -1;
2474 }
2475 return (*respValue);
2476}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002477} // namespace power_control
2478
2479int main(int argc, char* argv[])
2480{
Lei YU92caa4c2021-02-23 16:59:25 +08002481 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05302482
2483 if (argc > 1)
2484 {
2485 node = argv[1];
2486 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002487 lg2::info("Start Chassis power control service for host : {NODE}", "NODE",
2488 node);
Priyatharshan P70120512020-09-16 18:47:20 +05302489
Lei YU92caa4c2021-02-23 16:59:25 +08002490 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002491
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302492 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08002493 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302494 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002495 lg2::error("Host{NODE}: Error in Parsing...", "NODE", node);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302496 }
Naveen Mosesec972d82021-07-16 21:19:23 +05302497 /* Currently for single host based systems additional busname is added
2498 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
2499 Going forward for single hosts the old bus name without zero numbering
2500 will be removed when all other applications adapted to the
2501 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
2502
2503 if (node == "0")
2504 {
2505 // Request all the dbus names
2506 conn->request_name(hostDbusName.c_str());
2507 conn->request_name(chassisDbusName.c_str());
2508 conn->request_name(osDbusName.c_str());
2509 conn->request_name(buttonDbusName.c_str());
2510 conn->request_name(nmiDbusName.c_str());
2511 conn->request_name(rstCauseDbusName.c_str());
2512 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302513
Zev Weissc4005bd2021-09-01 22:30:23 -05002514 hostDbusName += node;
2515 chassisDbusName += node;
2516 osDbusName += node;
2517 buttonDbusName += node;
2518 nmiDbusName += node;
2519 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002520
Priyatharshan P70120512020-09-16 18:47:20 +05302521 // Request all the dbus names
2522 conn->request_name(hostDbusName.c_str());
2523 conn->request_name(chassisDbusName.c_str());
2524 conn->request_name(osDbusName.c_str());
2525 conn->request_name(buttonDbusName.c_str());
2526 conn->request_name(nmiDbusName.c_str());
2527 conn->request_name(rstCauseDbusName.c_str());
2528
2529 if (sioPwrGoodConfig.lineName.empty() ||
2530 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05302531 {
Lei YU92caa4c2021-02-23 16:59:25 +08002532 sioEnabled = false;
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002533 lg2::info("SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05302534 }
2535
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002536 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302537 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002538 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002539 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302540 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302541 {
2542 return -1;
2543 }
2544 }
Priyatharshan P70120512020-09-16 18:47:20 +05302545 else if (powerOkConfig.type == ConfigType::DBUS)
2546 {
2547
Patrick Williams439b9c32022-07-22 19:26:53 -05002548 static sdbusplus::bus::match_t powerOkEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002549 power_control::dbusGPIOMatcher(powerOkConfig, psPowerOKHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302550 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302551 else
2552 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002553 lg2::error("PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002554 return -1;
2555 }
2556
Lei YU92caa4c2021-02-23 16:59:25 +08002557 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002558 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05302559 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302560 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302561 {
Priyatharshan P70120512020-09-16 18:47:20 +05302562 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002563 sioPowerGoodHandler, sioPowerGoodLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302564 sioPowerGoodEvent))
2565 {
2566 return -1;
2567 }
2568 }
2569 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
2570 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002571 static sdbusplus::bus::match_t sioPwrGoodEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002572 power_control::dbusGPIOMatcher(sioPwrGoodConfig,
2573 sioPowerGoodHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302574 }
2575 else
2576 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002577 lg2::error(
Priyatharshan P70120512020-09-16 18:47:20 +05302578 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302579 return -1;
2580 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002581
Priyatharshan P19c47a32020-08-12 18:16:43 +05302582 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302583 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302584 {
Priyatharshan P70120512020-09-16 18:47:20 +05302585 if (!requestGPIOEvents(sioOnControlConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002586 sioOnControlHandler, sioOnControlLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302587 sioOnControlEvent))
2588 {
2589 return -1;
2590 }
2591 }
2592 else if (sioOnControlConfig.type == ConfigType::DBUS)
2593 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002594 static sdbusplus::bus::match_t sioOnControlEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002595 power_control::dbusGPIOMatcher(sioOnControlConfig,
2596 sioOnControlHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302597 }
2598 else
2599 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002600 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002601 "sioOnControl name should be configured from jsonconfig file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302602 return -1;
2603 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002604
Priyatharshan P19c47a32020-08-12 18:16:43 +05302605 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302606 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302607 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002608 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
Priyatharshan P70120512020-09-16 18:47:20 +05302609 sioS5Line, sioS5Event))
2610 {
2611 return -1;
2612 }
2613 }
2614 else if (sioS5Config.type == ConfigType::DBUS)
2615 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002616 static sdbusplus::bus::match_t sioS5EventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002617 power_control::dbusGPIOMatcher(sioS5Config, sioS5Handler);
Priyatharshan P70120512020-09-16 18:47:20 +05302618 }
2619 else
2620 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002621 lg2::error("sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302622 return -1;
2623 }
2624 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002625
2626 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302627 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002628 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002629 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
2630 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302631 {
2632 return -1;
2633 }
2634 }
Priyatharshan P70120512020-09-16 18:47:20 +05302635 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302636 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002637 static sdbusplus::bus::match_t powerButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002638 power_control::dbusGPIOMatcher(powerButtonConfig,
2639 powerButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002640 }
2641
2642 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302643 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002644 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002645 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
2646 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302647 {
2648 return -1;
2649 }
2650 }
Priyatharshan P70120512020-09-16 18:47:20 +05302651 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302652 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002653 static sdbusplus::bus::match_t resetButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002654 power_control::dbusGPIOMatcher(resetButtonConfig,
2655 resetButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002656 }
2657
2658 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302659 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302660 {
Priyatharshan P70120512020-09-16 18:47:20 +05302661 if (!nmiButtonConfig.lineName.empty())
2662 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002663 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302664 nmiButtonLine, nmiButtonEvent);
2665 }
2666 }
2667 else if (nmiButtonConfig.type == ConfigType::DBUS)
2668 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002669 static sdbusplus::bus::match_t nmiButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002670 power_control::dbusGPIOMatcher(nmiButtonConfig, nmiButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302671 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002672
2673 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302674 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302675 {
Priyatharshan P70120512020-09-16 18:47:20 +05302676 if (!idButtonConfig.lineName.empty())
2677 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002678 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302679 idButtonLine, idButtonEvent);
2680 }
2681 }
2682 else if (idButtonConfig.type == ConfigType::DBUS)
2683 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002684 static sdbusplus::bus::match_t idButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002685 power_control::dbusGPIOMatcher(idButtonConfig, idButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302686 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002687
Jason M. Billsfb957332021-01-28 13:18:46 -08002688#ifdef USE_PLT_RST
Patrick Williams439b9c32022-07-22 19:26:53 -05002689 sdbusplus::bus::match_t pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08002690 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08002691 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2692 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08002693 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08002694#endif
2695
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002696 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302697 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002698 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002699 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
2700 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302701 {
2702 return -1;
2703 }
2704 }
Priyatharshan P70120512020-09-16 18:47:20 +05302705 else if (postCompleteConfig.type == ConfigType::DBUS)
2706 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002707 static sdbusplus::bus::match_t postCompleteEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002708 power_control::dbusGPIOMatcher(postCompleteConfig,
2709 postCompleteHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302710 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302711 else
2712 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002713 lg2::error(
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002714 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002715 return -1;
2716 }
2717
2718 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05302719 if (!nmiOutConfig.lineName.empty())
2720 {
Ping Guo8643c792022-05-18 08:32:00 +08002721 setGPIOOutput(nmiOutConfig.lineName, nmiOutConfig.polarity, nmiOutLine);
Priyatharshan P70120512020-09-16 18:47:20 +05302722 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002723
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002724 // Initialize POWER_OUT and RESET_OUT GPIO.
2725 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05302726 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002727 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002728 if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
2729 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302730 {
2731 return -1;
2732 }
2733 }
2734 else
2735 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002736 lg2::error("powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002737 return -1;
2738 }
2739
Priyatharshan P70120512020-09-16 18:47:20 +05302740 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002741 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002742 if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
2743 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302744 {
2745 return -1;
2746 }
2747 }
2748 else
2749 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002750 lg2::error("ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002751 return -1;
2752 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002753 // Release line
2754 line.reset();
2755
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002756 // Initialize the power state
Lei YU92caa4c2021-02-23 16:59:25 +08002757 powerState = PowerState::off;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002758 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05302759
2760 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002761 {
Jean-Marie Verdun61b4a5b2021-09-19 08:53:28 -04002762 if (psPowerOKLine.get_value() > 0 ||
Lei YUa37c2472021-09-26 15:57:12 +08002763 (sioEnabled &&
2764 (sioPowerGoodLine.get_value() == sioPwrGoodConfig.polarity)))
Priyatharshan P70120512020-09-16 18:47:20 +05302765 {
2766 powerState = PowerState::on;
2767 }
2768 }
2769 else
2770 {
2771 if (getProperty(powerOkConfig))
2772 {
2773 powerState = PowerState::on;
2774 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002775 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002776 // Check if we need to start the Power Restore policy
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03002777 if (powerState != PowerState::on)
2778 {
2779 powerRestore.run();
2780 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002781
Lei YU92caa4c2021-02-23 16:59:25 +08002782 if (nmiOutLine)
2783 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002784
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002785 lg2::info("Initializing power state.");
Lei YU92caa4c2021-02-23 16:59:25 +08002786 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002787
2788 // Power Control Service
2789 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002790 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002791
2792 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05302793 hostIface =
2794 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
2795 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002796 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08002797 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002798 "RequestedHostTransition",
2799 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2800 [](const std::string& requested, std::string& resp) {
2801 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2802 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002803 // if power button is masked, ignore this
2804 if (!powerButtonMask)
2805 {
2806 sendPowerControlEvent(Event::gracefulPowerOffRequest);
2807 addRestartCause(RestartCause::command);
2808 }
2809 else
2810 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002811 lg2::info("Power Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002812 throw std::invalid_argument("Transition Request Masked");
2813 return 0;
2814 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002815 }
2816 else if (requested ==
2817 "xyz.openbmc_project.State.Host.Transition.On")
2818 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002819 // if power button is masked, ignore this
2820 if (!powerButtonMask)
2821 {
2822 sendPowerControlEvent(Event::powerOnRequest);
2823 addRestartCause(RestartCause::command);
2824 }
2825 else
2826 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002827 lg2::info("Power Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002828 throw std::invalid_argument("Transition Request Masked");
2829 return 0;
2830 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002831 }
2832 else if (requested ==
2833 "xyz.openbmc_project.State.Host.Transition.Reboot")
2834 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002835 // if power button is masked, ignore this
2836 if (!powerButtonMask)
2837 {
2838 sendPowerControlEvent(Event::powerCycleRequest);
2839 addRestartCause(RestartCause::command);
2840 }
2841 else
2842 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002843 lg2::info("Power Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002844 throw std::invalid_argument("Transition Request Masked");
2845 return 0;
2846 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002847 }
Jason M. Bills418ce112021-09-08 15:15:05 -07002848 else if (
2849 requested ==
2850 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot")
Jason M. Billse7520ba2020-01-31 11:19:03 -08002851 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002852 // if reset button is masked, ignore this
2853 if (!resetButtonMask)
2854 {
2855 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
2856 addRestartCause(RestartCause::command);
2857 }
2858 else
2859 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002860 lg2::info("Reset Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002861 throw std::invalid_argument("Transition Request Masked");
2862 return 0;
2863 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002864 }
Jason M. Bills418ce112021-09-08 15:15:05 -07002865 else if (
2866 requested ==
2867 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot")
Jason M. Billse7520ba2020-01-31 11:19:03 -08002868 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002869 // if reset button is masked, ignore this
2870 if (!resetButtonMask)
2871 {
2872 sendPowerControlEvent(Event::resetRequest);
2873 addRestartCause(RestartCause::command);
2874 }
2875 else
2876 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002877 lg2::info("Reset Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002878 throw std::invalid_argument("Transition Request Masked");
2879 return 0;
2880 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002881 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002882 else
2883 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002884 lg2::error("Unrecognized host state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002885 throw std::invalid_argument("Unrecognized Transition Request");
2886 return 0;
2887 }
2888 resp = requested;
2889 return 1;
2890 });
Lei YU92caa4c2021-02-23 16:59:25 +08002891 hostIface->register_property("CurrentHostState",
2892 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002893
Lei YU92caa4c2021-02-23 16:59:25 +08002894 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002895
2896 // Chassis Control Service
2897 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002898 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002899
2900 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002901 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05302902 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002903 "xyz.openbmc_project.State.Chassis");
2904
Lei YU92caa4c2021-02-23 16:59:25 +08002905 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002906 "RequestedPowerTransition",
2907 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
2908 [](const std::string& requested, std::string& resp) {
2909 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
2910 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002911 // if power button is masked, ignore this
2912 if (!powerButtonMask)
2913 {
2914 sendPowerControlEvent(Event::powerOffRequest);
2915 addRestartCause(RestartCause::command);
2916 }
2917 else
2918 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002919 lg2::info("Power Button Masked.");
Vernon Mauery2a269432021-07-14 10:00:21 -07002920 throw std::invalid_argument("Transition Request Masked");
2921 return 0;
2922 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002923 }
2924 else if (requested ==
2925 "xyz.openbmc_project.State.Chassis.Transition.On")
2926 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002927 // if power button is masked, ignore this
2928 if (!powerButtonMask)
2929 {
2930 sendPowerControlEvent(Event::powerOnRequest);
2931 addRestartCause(RestartCause::command);
2932 }
2933 else
2934 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002935 lg2::info("Power Button Masked.");
Vernon Mauery2a269432021-07-14 10:00:21 -07002936 throw std::invalid_argument("Transition Request Masked");
2937 return 0;
2938 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002939 }
2940 else if (requested ==
2941 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2942 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002943 // if power button is masked, ignore this
2944 if (!powerButtonMask)
2945 {
2946 sendPowerControlEvent(Event::powerCycleRequest);
2947 addRestartCause(RestartCause::command);
2948 }
2949 else
2950 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002951 lg2::info("Power Button Masked.");
Vernon Mauery2a269432021-07-14 10:00:21 -07002952 throw std::invalid_argument("Transition Request Masked");
2953 return 0;
2954 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002955 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002956 else
2957 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002958 lg2::error("Unrecognized chassis state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002959 throw std::invalid_argument("Unrecognized Transition Request");
2960 return 0;
2961 }
2962 resp = requested;
2963 return 1;
2964 });
Lei YU92caa4c2021-02-23 16:59:25 +08002965 chassisIface->register_property("CurrentPowerState",
2966 std::string(getChassisState(powerState)));
2967 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002968
Lei YU92caa4c2021-02-23 16:59:25 +08002969 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002970
Vijay Khemka04175c22020-10-09 14:28:11 -07002971#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002972 // Chassis System Service
2973 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002974 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002975
2976 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002977 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002978 "/xyz/openbmc_project/state/chassis_system0",
2979 "xyz.openbmc_project.State.Chassis");
2980
Lei YU92caa4c2021-02-23 16:59:25 +08002981 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002982 "RequestedPowerTransition",
2983 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
2984 [](const std::string& requested, std::string& resp) {
2985 if (requested ==
2986 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2987 {
Lei YU92caa4c2021-02-23 16:59:25 +08002988 systemReset();
2989 addRestartCause(RestartCause::command);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002990 }
2991 else
2992 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002993 lg2::error(
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002994 "Unrecognized chassis system state transition request.");
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002995 throw std::invalid_argument("Unrecognized Transition Request");
2996 return 0;
2997 }
2998 resp = requested;
2999 return 1;
3000 });
Lei YU92caa4c2021-02-23 16:59:25 +08003001 chassisSysIface->register_property(
3002 "CurrentPowerState", std::string(getChassisState(powerState)));
3003 chassisSysIface->register_property("LastStateChangeTime",
3004 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003005
Lei YU92caa4c2021-02-23 16:59:25 +08003006 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003007
Naveen Moses117c34e2021-05-26 20:10:51 +05303008 if (!slotPowerConfig.lineName.empty())
3009 {
3010 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3011 {
3012 return -1;
3013 }
3014
3015 slotPowerState = SlotPowerState::off;
3016 if (slotPowerLine.get_value() > 0)
3017 {
3018 slotPowerState = SlotPowerState::on;
3019 }
3020
3021 chassisSlotIface = chassisSysServer.add_interface(
3022 "/xyz/openbmc_project/state/chassis_system" + node,
3023 "xyz.openbmc_project.State.Chassis");
3024 chassisSlotIface->register_property(
3025 "RequestedPowerTransition",
3026 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3027 [](const std::string& requested, std::string& resp) {
3028 if (requested ==
3029 "xyz.openbmc_project.State.Chassis.Transition.On")
3030 {
3031 slotPowerOn();
3032 }
3033 else if (requested ==
3034 "xyz.openbmc_project.State.Chassis.Transition.Off")
3035 {
3036 slotPowerOff();
3037 }
Jason M. Bills418ce112021-09-08 15:15:05 -07003038 else if (
3039 requested ==
3040 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
Naveen Moses117c34e2021-05-26 20:10:51 +05303041 {
3042 slotPowerCycle();
3043 }
3044 else
3045 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003046 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07003047 "Unrecognized chassis system state transition request.\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05303048 throw std::invalid_argument(
3049 "Unrecognized Transition Request");
3050 return 0;
3051 }
3052 resp = requested;
3053 return 1;
3054 });
3055 chassisSlotIface->register_property(
3056 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3057 chassisSlotIface->register_property("LastStateChangeTime",
3058 getCurrentTimeMs());
3059 chassisSlotIface->initialize();
3060 }
3061#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003062 // Buttons Service
3063 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003064 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003065
Priyatharshan P70120512020-09-16 18:47:20 +05303066 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003067 {
Priyatharshan P70120512020-09-16 18:47:20 +05303068 // Power Button Interface
3069 power_control::powerButtonIface = buttonsServer.add_interface(
3070 "/xyz/openbmc_project/chassis/buttons/power",
3071 "xyz.openbmc_project.Chassis.Buttons");
3072
3073 powerButtonIface->register_property(
3074 "ButtonMasked", false, [](const bool requested, bool& current) {
3075 if (requested)
3076 {
3077 if (powerButtonMask)
3078 {
3079 return 1;
3080 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003081 if (!setGPIOOutput(powerOutConfig.lineName,
3082 !powerOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303083 powerButtonMask))
3084 {
3085 throw std::runtime_error("Failed to request GPIO");
3086 return 0;
3087 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003088 lg2::info("Power Button Masked.");
Priyatharshan P70120512020-09-16 18:47:20 +05303089 }
3090 else
3091 {
3092 if (!powerButtonMask)
3093 {
3094 return 1;
3095 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003096 lg2::info("Power Button Un-masked");
Priyatharshan P70120512020-09-16 18:47:20 +05303097 powerButtonMask.reset();
3098 }
3099 // Update the mask setting
3100 current = requested;
3101 return 1;
3102 });
3103
3104 // Check power button state
3105 bool powerButtonPressed;
3106 if (powerButtonConfig.type == ConfigType::GPIO)
3107 {
3108 powerButtonPressed = powerButtonLine.get_value() == 0;
3109 }
3110 else
3111 {
3112 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3113 }
3114
3115 powerButtonIface->register_property("ButtonPressed",
3116 powerButtonPressed);
3117
3118 powerButtonIface->initialize();
3119 }
3120
3121 if (!resetButtonConfig.lineName.empty())
3122 {
3123 // Reset Button Interface
3124
Lei YU92caa4c2021-02-23 16:59:25 +08003125 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003126 "/xyz/openbmc_project/chassis/buttons/reset",
3127 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003128
Lei YU92caa4c2021-02-23 16:59:25 +08003129 resetButtonIface->register_property(
John Wang6c090072020-09-30 13:32:16 +08003130 "ButtonMasked", false, [](const bool requested, bool& current) {
3131 if (requested)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003132 {
Lei YU92caa4c2021-02-23 16:59:25 +08003133 if (resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003134 {
3135 return 1;
3136 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003137 if (!setGPIOOutput(resetOutConfig.lineName,
3138 !resetOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303139 resetButtonMask))
John Wang6c090072020-09-30 13:32:16 +08003140 {
3141 throw std::runtime_error("Failed to request GPIO");
3142 return 0;
3143 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003144 lg2::info("Reset Button Masked.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003145 }
John Wang6c090072020-09-30 13:32:16 +08003146 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003147 {
Lei YU92caa4c2021-02-23 16:59:25 +08003148 if (!resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003149 {
3150 return 1;
3151 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003152 lg2::info("Reset Button Un-masked");
Lei YU92caa4c2021-02-23 16:59:25 +08003153 resetButtonMask.reset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003154 }
John Wang6c090072020-09-30 13:32:16 +08003155 // Update the mask setting
3156 current = requested;
3157 return 1;
3158 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003159
John Wang6c090072020-09-30 13:32:16 +08003160 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303161 bool resetButtonPressed;
3162 if (resetButtonConfig.type == ConfigType::GPIO)
3163 {
3164 resetButtonPressed = resetButtonLine.get_value() == 0;
3165 }
3166 else
3167 {
3168 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3169 }
3170
Lei YU92caa4c2021-02-23 16:59:25 +08003171 resetButtonIface->register_property("ButtonPressed",
3172 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003173
Lei YU92caa4c2021-02-23 16:59:25 +08003174 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003175 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003176
Lei YU92caa4c2021-02-23 16:59:25 +08003177 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003178 {
3179 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003180 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003181 "/xyz/openbmc_project/chassis/buttons/nmi",
3182 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003183
Lei YU92caa4c2021-02-23 16:59:25 +08003184 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003185 "ButtonMasked", false, [](const bool requested, bool& current) {
Lei YU92caa4c2021-02-23 16:59:25 +08003186 if (nmiButtonMasked == requested)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003187 {
3188 // NMI button mask is already set as requested, so no change
3189 return 1;
3190 }
3191 if (requested)
3192 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003193 lg2::info("NMI Button Masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003194 nmiButtonMasked = true;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003195 }
3196 else
3197 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003198 lg2::info("NMI Button Un-masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003199 nmiButtonMasked = false;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003200 }
3201 // Update the mask setting
Lei YU92caa4c2021-02-23 16:59:25 +08003202 current = nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003203 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003204 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003205
Vijay Khemka33a532d2019-11-14 16:50:35 -08003206 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303207 bool nmiButtonPressed;
3208 if (nmiButtonConfig.type == ConfigType::GPIO)
3209 {
3210 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3211 }
3212 else
3213 {
3214 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3215 }
3216
Lei YU92caa4c2021-02-23 16:59:25 +08003217 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003218
Lei YU92caa4c2021-02-23 16:59:25 +08003219 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003220 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003221
Lei YU92caa4c2021-02-23 16:59:25 +08003222 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003223 {
3224 // NMI out Service
3225 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003226 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003227
Vijay Khemka33a532d2019-11-14 16:50:35 -08003228 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303229 nmiOutIface = nmiOutServer.add_interface(
3230 "/xyz/openbmc_project/control/host" + node + "/nmi",
3231 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003232 nmiOutIface->register_method("NMI", nmiReset);
3233 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003234 }
Chen Yugang174ec662019-08-19 19:58:49 +08003235
Lei YU92caa4c2021-02-23 16:59:25 +08003236 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003237 {
3238 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003239 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003240 "/xyz/openbmc_project/chassis/buttons/id",
3241 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003242
Vijay Khemka33a532d2019-11-14 16:50:35 -08003243 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303244 bool idButtonPressed;
3245 if (idButtonConfig.type == ConfigType::GPIO)
3246 {
3247 idButtonPressed = idButtonLine.get_value() == 0;
3248 }
3249 else
3250 {
3251 idButtonPressed = getProperty(idButtonConfig) == 0;
3252 }
3253
Lei YU92caa4c2021-02-23 16:59:25 +08003254 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003255
Lei YU92caa4c2021-02-23 16:59:25 +08003256 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003257 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003258
3259 // OS State Service
3260 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003261 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003262
3263 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003264 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003265 "/xyz/openbmc_project/state/os",
3266 "xyz.openbmc_project.State.OperatingSystem.Status");
3267
3268 // Get the initial OS state based on POST complete
3269 // 0: Asserted, OS state is "Standby" (ready to boot)
3270 // 1: De-Asserted, OS state is "Inactive"
Tim Lee86239182021-12-23 11:46:01 +08003271 OperatingSystemStateStage osState;
Priyatharshan P70120512020-09-16 18:47:20 +05303272 if (postCompleteConfig.type == ConfigType::GPIO)
3273 {
Tim Lee86239182021-12-23 11:46:01 +08003274 osState = postCompleteLine.get_value() > 0
3275 ? OperatingSystemStateStage::Inactive
3276 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303277 }
3278 else
3279 {
Tim Lee86239182021-12-23 11:46:01 +08003280 osState = getProperty(postCompleteConfig) > 0
3281 ? OperatingSystemStateStage::Inactive
3282 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303283 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003284
Tim Lee86239182021-12-23 11:46:01 +08003285 osIface->register_property(
3286 "OperatingSystemState",
3287 std::string(getOperatingSystemStateStage(osState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003288
Lei YU92caa4c2021-02-23 16:59:25 +08003289 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003290
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003291 // Restart Cause Service
3292 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003293 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003294
3295 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003296 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303297 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003298 "xyz.openbmc_project.Control.Host.RestartCause");
3299
Lei YU92caa4c2021-02-23 16:59:25 +08003300 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003301 "RestartCause",
3302 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3303
Lei YU92caa4c2021-02-23 16:59:25 +08003304 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003305 "RequestedRestartCause",
3306 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3307 [](const std::string& requested, std::string& resp) {
3308 if (requested ==
3309 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3310 {
Lei YU92caa4c2021-02-23 16:59:25 +08003311 addRestartCause(RestartCause::watchdog);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003312 }
3313 else
3314 {
3315 throw std::invalid_argument(
3316 "Unrecognized RestartCause Request");
3317 return 0;
3318 }
3319
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003320 lg2::info("RestartCause requested: {RESTART_CAUSE}",
3321 "RESTART_CAUSE", requested);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003322 resp = requested;
3323 return 1;
3324 });
3325
Lei YU92caa4c2021-02-23 16:59:25 +08003326 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003327
Lei YU92caa4c2021-02-23 16:59:25 +08003328 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003329
Lei YU92caa4c2021-02-23 16:59:25 +08003330 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003331
3332 return 0;
3333}