blob: 950df479fe17ac51a47d6e23beb47282db655448 [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*/
Ed Tanousf61ca6f2019-08-15 15:09:05 -070016#include <sys/sysinfo.h>
17#include <systemd/sd-journal.h>
18
Jason M. Billse63dea02020-08-27 12:07:35 -070019#include <boost/asio/io_service.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070020#include <boost/asio/posix/stream_descriptor.hpp>
Jason M. Billse63dea02020-08-27 12:07:35 -070021#include <boost/asio/steady_timer.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070022#include <boost/container/flat_map.hpp>
Jason M. Bills7d4aaac2019-09-19 14:03:44 -070023#include <boost/container/flat_set.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070024#include <gpiod.hpp>
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053025#include <nlohmann/json.hpp>
Vijay Khemkafc1ecc52020-04-01 10:49:28 -070026#include <phosphor-logging/log.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070027#include <sdbusplus/asio/object_server.hpp>
Vijay Khemka2b6f4422020-05-29 11:13:23 -070028
29#include <filesystem>
30#include <fstream>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070031#include <string_view>
32
33namespace power_control
34{
35static boost::asio::io_service io;
36std::shared_ptr<sdbusplus::asio::connection> conn;
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053037
38static std::string node = "0";
39
Priyatharshan P70120512020-09-16 18:47:20 +053040enum class DbusConfigType
41{
42 name = 1,
43 path,
44 interface,
45 property
46};
47boost::container::flat_map<DbusConfigType, std::string> dbusParams = {
48 {DbusConfigType::name, "DbusName"},
49 {DbusConfigType::path, "Path"},
50 {DbusConfigType::interface, "Interface"},
51 {DbusConfigType::property, "Property"}};
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053052
Priyatharshan P70120512020-09-16 18:47:20 +053053enum class ConfigType
54{
55 GPIO = 1,
56 DBUS
57};
58
59struct ConfigData
60{
61 std::string name;
62 std::string lineName;
63 std::string dbusName;
64 std::string path;
65 std::string interface;
Jean-Marie Verdun50937e72021-08-31 09:15:49 -070066 bool polarity;
Priyatharshan P70120512020-09-16 18:47:20 +053067 ConfigType type;
68};
69
70static ConfigData powerOutConfig;
71static ConfigData powerOkConfig;
72static ConfigData resetOutConfig;
73static ConfigData nmiOutConfig;
74static ConfigData sioPwrGoodConfig;
75static ConfigData sioOnControlConfig;
76static ConfigData sioS5Config;
77static ConfigData postCompleteConfig;
78static ConfigData powerButtonConfig;
79static ConfigData resetButtonConfig;
80static ConfigData idButtonConfig;
81static ConfigData nmiButtonConfig;
Naveen Moses117c34e2021-05-26 20:10:51 +053082static ConfigData slotPowerConfig;
83
Priyatharshan P70120512020-09-16 18:47:20 +053084// map for storing list of gpio parameters whose config are to be read from x86
85// power control json config
86boost::container::flat_map<std::string, ConfigData*> powerSignalMap = {
87 {"PowerOut", &powerOutConfig},
88 {"PowerOk", &powerOkConfig},
89 {"ResetOut", &resetOutConfig},
90 {"NMIOut", &nmiOutConfig},
91 {"SioPowerGood", &sioPwrGoodConfig},
92 {"SioOnControl", &sioOnControlConfig},
93 {"SIOS5", &sioS5Config},
94 {"PostComplete", &postCompleteConfig},
95 {"PowerButton", &powerButtonConfig},
96 {"ResetButton", &resetButtonConfig},
97 {"IdButton", &idButtonConfig},
Naveen Moses117c34e2021-05-26 20:10:51 +053098 {"NMIButton", &nmiButtonConfig},
99 {"SlotPower", &slotPowerConfig}};
Priyatharshan P70120512020-09-16 18:47:20 +0530100
101static std::string hostDbusName = "xyz.openbmc_project.State.Host";
102static std::string chassisDbusName = "xyz.openbmc_project.State.Chassis";
103static std::string osDbusName = "xyz.openbmc_project.State.OperatingSystem";
104static std::string buttonDbusName = "xyz.openbmc_project.Chassis.Buttons";
105static std::string nmiDbusName = "xyz.openbmc_project.Control.Host.NMI";
106static std::string rstCauseDbusName =
107 "xyz.openbmc_project.Control.Host.RestartCause";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700108static std::shared_ptr<sdbusplus::asio::dbus_interface> hostIface;
109static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700110#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -0700111static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSysIface;
Naveen Moses117c34e2021-05-26 20:10:51 +0530112static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSlotIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700113#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700114static std::shared_ptr<sdbusplus::asio::dbus_interface> powerButtonIface;
115static std::shared_ptr<sdbusplus::asio::dbus_interface> resetButtonIface;
116static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiButtonIface;
117static std::shared_ptr<sdbusplus::asio::dbus_interface> osIface;
118static std::shared_ptr<sdbusplus::asio::dbus_interface> idButtonIface;
Chen Yugang174ec662019-08-19 19:58:49 +0800119static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiOutIface;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700120static std::shared_ptr<sdbusplus::asio::dbus_interface> restartCauseIface;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700121
122static gpiod::line powerButtonMask;
123static gpiod::line resetButtonMask;
124static bool nmiButtonMasked = false;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700125
Priyatharshan P70120512020-09-16 18:47:20 +0530126// This map contains all timer values that are to be read from json config
127boost::container::flat_map<std::string, int> TimerMap = {
Jason M. Billsaeefe042021-09-08 14:56:11 -0700128 {"PowerPulseMs", 200},
129 {"ForceOffPulseMs", 15000},
130 {"ResetPulseMs", 500},
131 {"PowerCycleMs", 5000},
132 {"SioPowerGoodWatchdogMs", 1000},
133 {"PsPowerOKWatchdogMs", 8000},
134 {"GracefulPowerOffS", (5 * 60)},
135 {"WarmResetCheckMs", 500},
136 {"PowerOffSaveMs", 7000},
137 {"SlotPowerCycleMs", 200}};
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700138const static std::filesystem::path powerControlDir = "/var/lib/power-control";
139const static constexpr std::string_view powerStateFile = "power-state";
140
141static bool nmiEnabled = true;
Priyatharshan P19c47a32020-08-12 18:16:43 +0530142static bool sioEnabled = true;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700143
144// Timers
145// Time holding GPIOs asserted
146static boost::asio::steady_timer gpioAssertTimer(io);
147// Time between off and on during a power cycle
148static boost::asio::steady_timer powerCycleTimer(io);
149// Time OS gracefully powering off
150static boost::asio::steady_timer gracefulPowerOffTimer(io);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700151// Time the warm reset check
152static boost::asio::steady_timer warmResetCheckTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700153// Time power supply power OK assertion on power-on
154static boost::asio::steady_timer psPowerOKWatchdogTimer(io);
155// Time SIO power good assertion on power-on
156static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io);
157// Time power-off state save for power loss tracking
158static boost::asio::steady_timer powerStateSaveTimer(io);
159// POH timer
160static boost::asio::steady_timer pohCounterTimer(io);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700161// Time when to allow restart cause updates
162static boost::asio::steady_timer restartCauseTimer(io);
Naveen Moses117c34e2021-05-26 20:10:51 +0530163static boost::asio::steady_timer slotPowerCycleTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700164
165// GPIO Lines and Event Descriptors
166static gpiod::line psPowerOKLine;
167static boost::asio::posix::stream_descriptor psPowerOKEvent(io);
168static gpiod::line sioPowerGoodLine;
169static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io);
170static gpiod::line sioOnControlLine;
171static boost::asio::posix::stream_descriptor sioOnControlEvent(io);
172static gpiod::line sioS5Line;
173static boost::asio::posix::stream_descriptor sioS5Event(io);
174static gpiod::line powerButtonLine;
175static boost::asio::posix::stream_descriptor powerButtonEvent(io);
176static gpiod::line resetButtonLine;
177static boost::asio::posix::stream_descriptor resetButtonEvent(io);
178static gpiod::line nmiButtonLine;
179static boost::asio::posix::stream_descriptor nmiButtonEvent(io);
180static gpiod::line idButtonLine;
181static boost::asio::posix::stream_descriptor idButtonEvent(io);
182static gpiod::line postCompleteLine;
183static boost::asio::posix::stream_descriptor postCompleteEvent(io);
184static gpiod::line nmiOutLine;
Naveen Moses117c34e2021-05-26 20:10:51 +0530185static gpiod::line slotPowerLine;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700186
187static constexpr uint8_t beepPowerFail = 8;
188
189static void beep(const uint8_t& beepPriority)
190{
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800191 std::string logMsg = "Beep with priority: " + std::to_string(beepPriority);
192 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700193
194 conn->async_method_call(
195 [](boost::system::error_code ec) {
196 if (ec)
197 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800198 std::string errMsg =
199 "beep returned error with async_method_call (ec = " +
200 ec.message();
201 phosphor::logging::log<phosphor::logging::level::ERR>(
202 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700203 return;
204 }
205 },
206 "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
207 "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
208}
209
210enum class PowerState
211{
212 on,
213 waitForPSPowerOK,
214 waitForSIOPowerGood,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700215 off,
216 transitionToOff,
217 gracefulTransitionToOff,
218 cycleOff,
219 transitionToCycleOff,
220 gracefulTransitionToCycleOff,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700221 checkForWarmReset,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700222};
223static PowerState powerState;
224static std::string getPowerStateName(PowerState state)
225{
226 switch (state)
227 {
228 case PowerState::on:
229 return "On";
230 break;
231 case PowerState::waitForPSPowerOK:
232 return "Wait for Power Supply Power OK";
233 break;
234 case PowerState::waitForSIOPowerGood:
235 return "Wait for SIO Power Good";
236 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700237 case PowerState::off:
238 return "Off";
239 break;
240 case PowerState::transitionToOff:
241 return "Transition to Off";
242 break;
243 case PowerState::gracefulTransitionToOff:
244 return "Graceful Transition to Off";
245 break;
246 case PowerState::cycleOff:
247 return "Power Cycle Off";
248 break;
249 case PowerState::transitionToCycleOff:
250 return "Transition to Power Cycle Off";
251 break;
252 case PowerState::gracefulTransitionToCycleOff:
253 return "Graceful Transition to Power Cycle Off";
254 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700255 case PowerState::checkForWarmReset:
256 return "Check for Warm Reset";
257 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700258 default:
259 return "unknown state: " + std::to_string(static_cast<int>(state));
260 break;
261 }
262}
263static void logStateTransition(const PowerState state)
264{
Naveen Mosesec972d82021-07-16 21:19:23 +0530265 std::string logMsg = "Host" + node + ": Moving to \"" +
266 getPowerStateName(state) + "\" state";
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700267 phosphor::logging::log<phosphor::logging::level::INFO>(
268 logMsg.c_str(),
Vijay Khemkad6c5ad12020-05-27 14:57:52 -0700269 phosphor::logging::entry("STATE=%s", getPowerStateName(state).c_str()),
Naveen Mosesec972d82021-07-16 21:19:23 +0530270 phosphor::logging::entry("HOST=%s", node.c_str()));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700271}
272
273enum class Event
274{
275 psPowerOKAssert,
276 psPowerOKDeAssert,
277 sioPowerGoodAssert,
278 sioPowerGoodDeAssert,
279 sioS5Assert,
280 sioS5DeAssert,
Jason M. Billsfb957332021-01-28 13:18:46 -0800281 pltRstAssert,
282 pltRstDeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700283 postCompleteAssert,
284 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700285 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700286 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700287 powerCycleTimerExpired,
288 psPowerOKWatchdogTimerExpired,
289 sioPowerGoodWatchdogTimerExpired,
290 gracefulPowerOffTimerExpired,
291 powerOnRequest,
292 powerOffRequest,
293 powerCycleRequest,
294 resetRequest,
295 gracefulPowerOffRequest,
296 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700297 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700298};
299static std::string getEventName(Event event)
300{
301 switch (event)
302 {
303 case Event::psPowerOKAssert:
304 return "power supply power OK assert";
305 break;
306 case Event::psPowerOKDeAssert:
307 return "power supply power OK de-assert";
308 break;
309 case Event::sioPowerGoodAssert:
310 return "SIO power good assert";
311 break;
312 case Event::sioPowerGoodDeAssert:
313 return "SIO power good de-assert";
314 break;
315 case Event::sioS5Assert:
316 return "SIO S5 assert";
317 break;
318 case Event::sioS5DeAssert:
319 return "SIO S5 de-assert";
320 break;
Jason M. Billsfb957332021-01-28 13:18:46 -0800321 case Event::pltRstAssert:
322 return "PLT_RST assert";
323 break;
324 case Event::pltRstDeAssert:
325 return "PLT_RST de-assert";
326 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700327 case Event::postCompleteAssert:
328 return "POST Complete assert";
329 break;
330 case Event::postCompleteDeAssert:
331 return "POST Complete de-assert";
332 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700333 case Event::powerButtonPressed:
334 return "power button pressed";
335 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700336 case Event::resetButtonPressed:
337 return "reset button pressed";
338 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700339 case Event::powerCycleTimerExpired:
340 return "power cycle timer expired";
341 break;
342 case Event::psPowerOKWatchdogTimerExpired:
343 return "power supply power OK watchdog timer expired";
344 break;
345 case Event::sioPowerGoodWatchdogTimerExpired:
346 return "SIO power good watchdog timer expired";
347 break;
348 case Event::gracefulPowerOffTimerExpired:
349 return "graceful power-off timer expired";
350 break;
351 case Event::powerOnRequest:
352 return "power-on request";
353 break;
354 case Event::powerOffRequest:
355 return "power-off request";
356 break;
357 case Event::powerCycleRequest:
358 return "power-cycle request";
359 break;
360 case Event::resetRequest:
361 return "reset request";
362 break;
363 case Event::gracefulPowerOffRequest:
364 return "graceful power-off request";
365 break;
366 case Event::gracefulPowerCycleRequest:
367 return "graceful power-cycle request";
368 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700369 case Event::warmResetDetected:
370 return "warm reset detected";
371 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700372 default:
373 return "unknown event: " + std::to_string(static_cast<int>(event));
374 break;
375 }
376}
377static void logEvent(const std::string_view stateHandler, const Event event)
378{
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700379 std::string logMsg{stateHandler};
380 logMsg += ": " + getEventName(event) + " event received";
381 phosphor::logging::log<phosphor::logging::level::INFO>(
382 logMsg.c_str(),
383 phosphor::logging::entry("EVENT=%s", getEventName(event).c_str()));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700384}
385
386// Power state handlers
387static void powerStateOn(const Event event);
388static void powerStateWaitForPSPowerOK(const Event event);
389static void powerStateWaitForSIOPowerGood(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700390static void powerStateOff(const Event event);
391static void powerStateTransitionToOff(const Event event);
392static void powerStateGracefulTransitionToOff(const Event event);
393static void powerStateCycleOff(const Event event);
394static void powerStateTransitionToCycleOff(const Event event);
395static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700396static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700397
398static std::function<void(const Event)> getPowerStateHandler(PowerState state)
399{
400 switch (state)
401 {
402 case PowerState::on:
403 return powerStateOn;
404 break;
405 case PowerState::waitForPSPowerOK:
406 return powerStateWaitForPSPowerOK;
407 break;
408 case PowerState::waitForSIOPowerGood:
409 return powerStateWaitForSIOPowerGood;
410 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700411 case PowerState::off:
412 return powerStateOff;
413 break;
414 case PowerState::transitionToOff:
415 return powerStateTransitionToOff;
416 break;
417 case PowerState::gracefulTransitionToOff:
418 return powerStateGracefulTransitionToOff;
419 break;
420 case PowerState::cycleOff:
421 return powerStateCycleOff;
422 break;
423 case PowerState::transitionToCycleOff:
424 return powerStateTransitionToCycleOff;
425 break;
426 case PowerState::gracefulTransitionToCycleOff:
427 return powerStateGracefulTransitionToCycleOff;
428 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700429 case PowerState::checkForWarmReset:
430 return powerStateCheckForWarmReset;
431 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700432 default:
Zev Weiss047bcb52020-08-20 21:28:11 +0000433 return nullptr;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700434 break;
435 }
436};
437
438static void sendPowerControlEvent(const Event event)
439{
440 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
441 if (handler == nullptr)
442 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800443 std::string errMsg = "Failed to find handler for power state: " +
444 std::to_string(static_cast<int>(powerState));
445 phosphor::logging::log<phosphor::logging::level::INFO>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700446 return;
447 }
448 handler(event);
449}
450
451static uint64_t getCurrentTimeMs()
452{
453 struct timespec time = {};
454
455 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
456 {
457 return 0;
458 }
459 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
460 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
461
462 return currentTimeMs;
463}
464
465static constexpr std::string_view getHostState(const PowerState state)
466{
467 switch (state)
468 {
469 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700470 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700471 case PowerState::gracefulTransitionToCycleOff:
472 return "xyz.openbmc_project.State.Host.HostState.Running";
473 break;
474 case PowerState::waitForPSPowerOK:
475 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700476 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700477 case PowerState::transitionToOff:
478 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700479 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700480 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700481 return "xyz.openbmc_project.State.Host.HostState.Off";
482 break;
483 default:
484 return "";
485 break;
486 }
487};
488static constexpr std::string_view getChassisState(const PowerState state)
489{
490 switch (state)
491 {
492 case PowerState::on:
493 case PowerState::transitionToOff:
494 case PowerState::gracefulTransitionToOff:
495 case PowerState::transitionToCycleOff:
496 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700497 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700498 return "xyz.openbmc_project.State.Chassis.PowerState.On";
499 break;
500 case PowerState::waitForPSPowerOK:
501 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700502 case PowerState::off:
503 case PowerState::cycleOff:
504 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
505 break;
506 default:
507 return "";
508 break;
509 }
510};
Naveen Moses117c34e2021-05-26 20:10:51 +0530511#ifdef CHASSIS_SYSTEM_RESET
512enum class SlotPowerState
513{
514 on,
515 off,
516};
517static SlotPowerState slotPowerState;
518static constexpr std::string_view getSlotState(const SlotPowerState state)
519{
520 switch (state)
521 {
522 case SlotPowerState::on:
523 return "xyz.openbmc_project.State.Chassis.PowerState.On";
524 break;
525 case SlotPowerState::off:
526 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
527 break;
528 default:
529 return "";
530 break;
531 }
532};
533static void setSlotPowerState(const SlotPowerState state)
534{
535 slotPowerState = state;
536 chassisSlotIface->set_property("CurrentPowerState",
537 std::string(getSlotState(slotPowerState)));
538 chassisSlotIface->set_property("LastStateChangeTime", getCurrentTimeMs());
539}
540#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700541static void savePowerState(const PowerState state)
542{
543 powerStateSaveTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -0700544 std::chrono::milliseconds(TimerMap["PowerOffSaveMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700545 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
546 if (ec)
547 {
548 // operation_aborted is expected if timer is canceled before
549 // completion.
550 if (ec != boost::asio::error::operation_aborted)
551 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800552 std::string errMsg =
553 "Power-state save async_wait failed: " + ec.message();
554 phosphor::logging::log<phosphor::logging::level::ERR>(
555 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700556 }
557 return;
558 }
559 std::ofstream powerStateStream(powerControlDir / powerStateFile);
560 powerStateStream << getChassisState(state);
561 });
562}
563static void setPowerState(const PowerState state)
564{
565 powerState = state;
566 logStateTransition(state);
567
568 hostIface->set_property("CurrentHostState",
569 std::string(getHostState(powerState)));
570
571 chassisIface->set_property("CurrentPowerState",
572 std::string(getChassisState(powerState)));
573 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
574
575 // Save the power state for the restore policy
576 savePowerState(state);
577}
578
579enum class RestartCause
580{
581 command,
582 resetButton,
583 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700584 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700585 powerPolicyOn,
586 powerPolicyRestore,
587 softReset,
588};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700589static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700590static std::string getRestartCause(RestartCause cause)
591{
592 switch (cause)
593 {
594 case RestartCause::command:
595 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
596 break;
597 case RestartCause::resetButton:
598 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
599 break;
600 case RestartCause::powerButton:
601 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
602 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700603 case RestartCause::watchdog:
604 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
605 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700606 case RestartCause::powerPolicyOn:
Jason M. Bills418ce112021-09-08 15:15:05 -0700607 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyAlwaysOn";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700608 break;
609 case RestartCause::powerPolicyRestore:
Jason M. Bills418ce112021-09-08 15:15:05 -0700610 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyPreviousState";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700611 break;
612 case RestartCause::softReset:
613 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
614 break;
615 default:
616 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
617 break;
618 }
619}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700620static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700621{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700622 // Add this to the set of causes for this restart
623 causeSet.insert(cause);
624}
625static void clearRestartCause()
626{
627 // Clear the set for the next restart
628 causeSet.clear();
629}
630static void setRestartCauseProperty(const std::string& cause)
631{
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800632 std::string logMsg = "RestartCause set to " + cause;
633 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700634 restartCauseIface->set_property("RestartCause", cause);
635}
Rashmi RV89f61312020-01-22 15:41:50 +0530636
637static void resetACBootProperty()
638{
639 if ((causeSet.contains(RestartCause::command)) ||
640 (causeSet.contains(RestartCause::softReset)))
641 {
642 conn->async_method_call(
643 [](boost::system::error_code ec) {
644 if (ec)
645 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800646 phosphor::logging::log<phosphor::logging::level::ERR>(
647 "failed to reset ACBoot property");
Rashmi RV89f61312020-01-22 15:41:50 +0530648 }
649 },
650 "xyz.openbmc_project.Settings",
651 "/xyz/openbmc_project/control/host0/ac_boot",
652 "org.freedesktop.DBus.Properties", "Set",
653 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
654 std::variant<std::string>{"False"});
655 }
656}
657
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700658static void setRestartCause()
659{
660 // Determine the actual restart cause based on the set of causes
661 std::string restartCause =
662 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
663 if (causeSet.contains(RestartCause::watchdog))
664 {
665 restartCause = getRestartCause(RestartCause::watchdog);
666 }
667 else if (causeSet.contains(RestartCause::command))
668 {
669 restartCause = getRestartCause(RestartCause::command);
670 }
671 else if (causeSet.contains(RestartCause::resetButton))
672 {
673 restartCause = getRestartCause(RestartCause::resetButton);
674 }
675 else if (causeSet.contains(RestartCause::powerButton))
676 {
677 restartCause = getRestartCause(RestartCause::powerButton);
678 }
679 else if (causeSet.contains(RestartCause::powerPolicyOn))
680 {
681 restartCause = getRestartCause(RestartCause::powerPolicyOn);
682 }
683 else if (causeSet.contains(RestartCause::powerPolicyRestore))
684 {
685 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
686 }
687 else if (causeSet.contains(RestartCause::softReset))
688 {
689 restartCause = getRestartCause(RestartCause::softReset);
690 }
691
692 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700693}
694
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700695static void systemPowerGoodFailedLog()
696{
697 sd_journal_send(
698 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
699 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
700 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700701 TimerMap["SioPowerGoodWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700702}
703
704static void psPowerOKFailedLog()
705{
706 sd_journal_send(
707 "MESSAGE=PowerControl: power supply power good failed to assert",
708 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
709 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700710 TimerMap["PsPowerOKWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700711}
712
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700713static void powerRestorePolicyLog()
714{
715 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
716 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
717 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
718}
719
720static void powerButtonPressLog()
721{
722 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
723 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
724 "OpenBMC.0.1.PowerButtonPressed", NULL);
725}
726
727static void resetButtonPressLog()
728{
729 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
730 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
731 "OpenBMC.0.1.ResetButtonPressed", NULL);
732}
733
734static void nmiButtonPressLog()
735{
736 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
737 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
738 "OpenBMC.0.1.NMIButtonPressed", NULL);
739}
740
741static void nmiDiagIntLog()
742{
743 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
744 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
745 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
746}
747
748static int initializePowerStateStorage()
749{
750 // create the power control directory if it doesn't exist
751 std::error_code ec;
752 if (!(std::filesystem::create_directories(powerControlDir, ec)))
753 {
754 if (ec.value() != 0)
755 {
Zev Weiss6b8e3e02021-09-01 22:36:03 -0500756 std::string errMsg = "failed to create " +
757 powerControlDir.string() + ": " + ec.message();
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800758 phosphor::logging::log<phosphor::logging::level::ERR>(
759 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700760 return -1;
761 }
762 }
763 // Create the power state file if it doesn't exist
764 if (!std::filesystem::exists(powerControlDir / powerStateFile))
765 {
766 std::ofstream powerStateStream(powerControlDir / powerStateFile);
767 powerStateStream << getChassisState(powerState);
768 }
769 return 0;
770}
771
772static bool wasPowerDropped()
773{
774 std::ifstream powerStateStream(powerControlDir / powerStateFile);
775 if (!powerStateStream.is_open())
776 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800777 phosphor::logging::log<phosphor::logging::level::ERR>(
778 "Failed to open power state file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700779 return false;
780 }
781
782 std::string state;
783 std::getline(powerStateStream, state);
784 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
785}
786
787static void invokePowerRestorePolicy(const std::string& policy)
788{
789 // Async events may call this twice, but we only want to run once
790 static bool policyInvoked = false;
791 if (policyInvoked)
792 {
793 return;
794 }
795 policyInvoked = true;
796
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800797 std::string logMsg = "Power restore delay expired, invoking " + policy;
798 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700799 if (policy ==
800 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
801 {
802 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700803 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700804 }
Jason M. Bills418ce112021-09-08 15:15:05 -0700805 else if (policy ==
806 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore")
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700807 {
808 if (wasPowerDropped())
809 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800810 phosphor::logging::log<phosphor::logging::level::INFO>(
811 "Power was dropped, restoring Host On state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700812 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700813 setRestartCauseProperty(
814 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700815 }
816 else
817 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800818 phosphor::logging::log<phosphor::logging::level::INFO>(
819 "No power drop, restoring Host Off state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700820 }
821 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -0700822 // We're done with the previous power state for the restore policy, so store
823 // the current state
824 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700825}
826
827static void powerRestorePolicyDelay(int delay)
828{
829 // Async events may call this twice, but we only want to run once
830 static bool delayStarted = false;
831 if (delayStarted)
832 {
833 return;
834 }
835 delayStarted = true;
836 // Calculate the delay from now to meet the requested delay
837 // Subtract the approximate uboot time
838 static constexpr const int ubootSeconds = 20;
839 delay -= ubootSeconds;
840 // Subtract the time since boot
841 struct sysinfo info = {};
842 if (sysinfo(&info) == 0)
843 {
844 delay -= info.uptime;
845 }
846 // 0 is the minimum delay
847 delay = std::max(delay, 0);
848
849 static boost::asio::steady_timer powerRestorePolicyTimer(io);
850 powerRestorePolicyTimer.expires_after(std::chrono::seconds(delay));
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800851 std::string logMsg =
852 "Power restore delay of " + std::to_string(delay) + " seconds started";
853 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700854 powerRestorePolicyTimer.async_wait([](const boost::system::error_code ec) {
855 if (ec)
856 {
857 // operation_aborted is expected if timer is canceled before
858 // completion.
859 if (ec != boost::asio::error::operation_aborted)
860 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800861 std::string errMsg =
862 "power restore policy async_wait failed: " + ec.message();
863 phosphor::logging::log<phosphor::logging::level::ERR>(
864 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700865 }
866 return;
867 }
868 // Get Power Restore Policy
869 // In case PowerRestorePolicy is not available, set a match for it
870 static std::unique_ptr<sdbusplus::bus::match::match>
871 powerRestorePolicyMatch = std::make_unique<
872 sdbusplus::bus::match::match>(
873 *conn,
874 "type='signal',interface='org.freedesktop.DBus.Properties',"
875 "member='PropertiesChanged',arg0namespace='xyz.openbmc_"
876 "project.Control.Power.RestorePolicy'",
877 [](sdbusplus::message::message& msg) {
878 std::string interfaceName;
879 boost::container::flat_map<std::string,
880 std::variant<std::string>>
881 propertiesChanged;
882 std::string policy;
883 try
884 {
885 msg.read(interfaceName, propertiesChanged);
886 policy = std::get<std::string>(
887 propertiesChanged.begin()->second);
888 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -0500889 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700890 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800891 phosphor::logging::log<phosphor::logging::level::ERR>(
892 "Unable to read power restore policy value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700893 powerRestorePolicyMatch.reset();
894 return;
895 }
896 invokePowerRestorePolicy(policy);
897 powerRestorePolicyMatch.reset();
898 });
899
900 // Check if it's already on DBus
901 conn->async_method_call(
902 [](boost::system::error_code ec,
903 const std::variant<std::string>& policyProperty) {
904 if (ec)
905 {
906 return;
907 }
908 powerRestorePolicyMatch.reset();
909 const std::string* policy =
910 std::get_if<std::string>(&policyProperty);
911 if (policy == nullptr)
912 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800913 phosphor::logging::log<phosphor::logging::level::ERR>(
914 "Unable to read power restore policy value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700915 return;
916 }
917 invokePowerRestorePolicy(*policy);
918 },
919 "xyz.openbmc_project.Settings",
920 "/xyz/openbmc_project/control/host0/power_restore_policy",
921 "org.freedesktop.DBus.Properties", "Get",
922 "xyz.openbmc_project.Control.Power.RestorePolicy",
923 "PowerRestorePolicy");
924 });
925}
926
927static void powerRestorePolicyStart()
928{
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800929 phosphor::logging::log<phosphor::logging::level::INFO>(
930 "Power restore policy started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700931 powerRestorePolicyLog();
932
933 // Get the desired delay time
934 // In case PowerRestoreDelay is not available, set a match for it
935 static std::unique_ptr<sdbusplus::bus::match::match>
936 powerRestoreDelayMatch = std::make_unique<sdbusplus::bus::match::match>(
937 *conn,
938 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
939 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Control."
940 "Power.RestoreDelay'",
941 [](sdbusplus::message::message& msg) {
942 std::string interfaceName;
943 boost::container::flat_map<std::string, std::variant<uint16_t>>
944 propertiesChanged;
945 int delay = 0;
946 try
947 {
948 msg.read(interfaceName, propertiesChanged);
949 delay =
950 std::get<uint16_t>(propertiesChanged.begin()->second);
951 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -0500952 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700953 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800954 phosphor::logging::log<phosphor::logging::level::ERR>(
955 "Unable to read power restore delay value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700956 powerRestoreDelayMatch.reset();
957 return;
958 }
959 powerRestorePolicyDelay(delay);
960 powerRestoreDelayMatch.reset();
961 });
962
963 // Check if it's already on DBus
964 conn->async_method_call(
965 [](boost::system::error_code ec,
966 const std::variant<uint16_t>& delayProperty) {
967 if (ec)
968 {
969 return;
970 }
971 powerRestoreDelayMatch.reset();
972 const uint16_t* delay = std::get_if<uint16_t>(&delayProperty);
973 if (delay == nullptr)
974 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800975 phosphor::logging::log<phosphor::logging::level::ERR>(
976 "Unable to read power restore delay value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700977 return;
978 }
979 powerRestorePolicyDelay(*delay);
980 },
981 "xyz.openbmc_project.Settings",
982 "/xyz/openbmc_project/control/power_restore_delay",
983 "org.freedesktop.DBus.Properties", "Get",
984 "xyz.openbmc_project.Control.Power.RestoreDelay", "PowerRestoreDelay");
985}
986
987static void powerRestorePolicyCheck()
988{
989 // In case ACBoot is not available, set a match for it
990 static std::unique_ptr<sdbusplus::bus::match::match> acBootMatch =
991 std::make_unique<sdbusplus::bus::match::match>(
992 *conn,
993 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
994 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Common."
995 "ACBoot'",
996 [](sdbusplus::message::message& msg) {
997 std::string interfaceName;
998 boost::container::flat_map<std::string,
999 std::variant<std::string>>
1000 propertiesChanged;
1001 std::string acBoot;
1002 try
1003 {
1004 msg.read(interfaceName, propertiesChanged);
1005 acBoot = std::get<std::string>(
1006 propertiesChanged.begin()->second);
1007 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05001008 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001009 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001010 phosphor::logging::log<phosphor::logging::level::ERR>(
1011 "Unable to read AC Boot status");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001012 acBootMatch.reset();
1013 return;
1014 }
1015 if (acBoot == "Unknown")
1016 {
1017 return;
1018 }
1019 if (acBoot == "True")
1020 {
1021 // Start the Power Restore policy
1022 powerRestorePolicyStart();
1023 }
1024 acBootMatch.reset();
1025 });
1026
1027 // Check if it's already on DBus
1028 conn->async_method_call(
1029 [](boost::system::error_code ec,
1030 const std::variant<std::string>& acBootProperty) {
1031 if (ec)
1032 {
1033 return;
1034 }
1035 const std::string* acBoot =
1036 std::get_if<std::string>(&acBootProperty);
1037 if (acBoot == nullptr)
1038 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001039 phosphor::logging::log<phosphor::logging::level::ERR>(
1040 "Unable to read AC Boot status");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001041 return;
1042 }
1043 if (*acBoot == "Unknown")
1044 {
1045 return;
1046 }
1047 if (*acBoot == "True")
1048 {
1049 // Start the Power Restore policy
1050 powerRestorePolicyStart();
1051 }
1052 acBootMatch.reset();
1053 },
1054 "xyz.openbmc_project.Settings",
1055 "/xyz/openbmc_project/control/host0/ac_boot",
1056 "org.freedesktop.DBus.Properties", "Get",
1057 "xyz.openbmc_project.Common.ACBoot", "ACBoot");
1058}
1059
Zev Weiss676ef2c2021-09-02 21:54:02 -05001060static void waitForGPIOEvent(const std::string& name,
1061 const std::function<void(bool)>& eventHandler,
1062 gpiod::line& line,
1063 boost::asio::posix::stream_descriptor& event)
1064{
1065 event.async_wait(
1066 boost::asio::posix::stream_descriptor::wait_read,
1067 [&name, eventHandler, &line,
1068 &event](const boost::system::error_code ec) {
1069 if (ec)
1070 {
1071 std::string errMsg =
1072 name + " fd handler error: " + ec.message();
1073 phosphor::logging::log<phosphor::logging::level::ERR>(
1074 errMsg.c_str());
1075 // TODO: throw here to force power-control to restart?
1076 return;
1077 }
1078 gpiod::line_event line_event = line.event_read();
1079 eventHandler(line_event.event_type ==
1080 gpiod::line_event::RISING_EDGE);
1081 waitForGPIOEvent(name, eventHandler, line, event);
1082 });
1083}
1084
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001085static bool requestGPIOEvents(
Zev Weiss676ef2c2021-09-02 21:54:02 -05001086 const std::string& name, const std::function<void(bool)>& handler,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001087 gpiod::line& gpioLine,
1088 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
1089{
1090 // Find the GPIO line
1091 gpioLine = gpiod::find_line(name);
1092 if (!gpioLine)
1093 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001094 std::string errMsg = "Failed to find the " + name + " line";
1095 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001096 return false;
1097 }
1098
1099 try
1100 {
1101 gpioLine.request(
Jason M. Bills9fd8ac22021-10-21 15:14:17 -07001102 {"power-control", gpiod::line_request::EVENT_BOTH_EDGES, {}});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001103 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05001104 catch (const std::exception&)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001105 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001106 std::string errMsg = "Failed to request events for " + name;
1107 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001108 return false;
1109 }
1110
1111 int gpioLineFd = gpioLine.event_get_fd();
1112 if (gpioLineFd < 0)
1113 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001114 std::string errMsg = "Failed to name " + name + " fd";
1115 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001116 return false;
1117 }
1118
1119 gpioEventDescriptor.assign(gpioLineFd);
1120
Zev Weiss676ef2c2021-09-02 21:54:02 -05001121 waitForGPIOEvent(name, handler, gpioLine, gpioEventDescriptor);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001122 return true;
1123}
1124
1125static bool setGPIOOutput(const std::string& name, const int value,
1126 gpiod::line& gpioLine)
1127{
1128 // Find the GPIO line
1129 gpioLine = gpiod::find_line(name);
1130 if (!gpioLine)
1131 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001132 std::string errMsg = "Failed to find the " + name + " line";
1133 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001134 return false;
1135 }
1136
1137 // Request GPIO output to specified value
1138 try
1139 {
Jason M. Bills9fd8ac22021-10-21 15:14:17 -07001140 gpioLine.request(
1141 {__FUNCTION__, gpiod::line_request::DIRECTION_OUTPUT, {}}, value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001142 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05001143 catch (const std::exception&)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001144 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001145 std::string errMsg = "Failed to request " + name + " output";
1146 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001147 return false;
1148 }
1149
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001150 std::string logMsg = name + " set to " + std::to_string(value);
1151 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001152 return true;
1153}
1154
1155static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1156 const std::string& name, const int value,
1157 const int durationMs)
1158{
1159 // Set the masked GPIO line to the specified value
1160 maskedGPIOLine.set_value(value);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001161 std::string logMsg = name + " set to " + std::to_string(value);
1162 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001163 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001164 gpioAssertTimer.async_wait([maskedGPIOLine, value,
1165 name](const boost::system::error_code ec) {
1166 // Set the masked GPIO line back to the opposite value
1167 maskedGPIOLine.set_value(!value);
1168 std::string logMsg = name + " released";
1169 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
1170 if (ec)
1171 {
1172 // operation_aborted is expected if timer is canceled before
1173 // completion.
1174 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001175 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001176 std::string errMsg =
1177 name + " async_wait failed: " + ec.message();
1178 phosphor::logging::log<phosphor::logging::level::ERR>(
1179 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001180 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001181 }
1182 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001183 return 0;
1184}
1185
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001186static int setGPIOOutputForMs(const ConfigData& config, const int value,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001187 const int durationMs)
1188{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001189 // If the requested GPIO is masked, use the mask line to set the output
1190 if (powerButtonMask && config.lineName == powerOutConfig.lineName)
1191 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001192 return setMaskedGPIOOutputForMs(powerButtonMask, config.lineName, value,
1193 durationMs);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001194 }
1195 if (resetButtonMask && config.lineName == resetOutConfig.lineName)
1196 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001197 return setMaskedGPIOOutputForMs(resetButtonMask, config.lineName, value,
1198 durationMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001199 }
1200
1201 // No mask set, so request and set the GPIO normally
1202 gpiod::line gpioLine;
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001203 if (!setGPIOOutput(config.lineName, value, gpioLine))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001204 {
1205 return -1;
1206 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001207 const std::string name = config.lineName;
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001208
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001209 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001210 gpioAssertTimer.async_wait([gpioLine, value,
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001211 name](const boost::system::error_code ec) {
1212 // Set the GPIO line back to the opposite value
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001213 gpioLine.set_value(!value);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001214 std::string logMsg = name + " released";
1215 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
1216 if (ec)
1217 {
1218 // operation_aborted is expected if timer is canceled before
1219 // completion.
1220 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001221 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001222 std::string errMsg =
1223 name + " async_wait failed: " + ec.message();
1224 phosphor::logging::log<phosphor::logging::level::ERR>(
1225 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001226 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001227 }
1228 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001229 return 0;
1230}
1231
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001232static int assertGPIOForMs(const ConfigData& config, const int durationMs)
1233{
1234 return setGPIOOutputForMs(config, config.polarity, durationMs);
1235}
1236
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001237static void powerOn()
1238{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001239 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001240}
Naveen Moses117c34e2021-05-26 20:10:51 +05301241#ifdef CHASSIS_SYSTEM_RESET
1242static int slotPowerOn()
1243{
1244 if (power_control::slotPowerState != power_control::SlotPowerState::on)
1245 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001246
Naveen Moses117c34e2021-05-26 20:10:51 +05301247 slotPowerLine.set_value(1);
1248
1249 if (slotPowerLine.get_value() > 0)
1250 {
1251 setSlotPowerState(SlotPowerState::on);
1252 phosphor::logging::log<phosphor::logging::level::INFO>(
1253 "Slot Power is switched On\n");
1254 }
1255 else
1256 {
1257 return -1;
1258 }
1259 }
1260 else
1261 {
1262 phosphor::logging::log<phosphor::logging::level::INFO>(
1263 "Slot Power is already in 'On' state\n");
1264 return -1;
1265 }
1266 return 0;
1267}
1268static int slotPowerOff()
1269{
1270 if (power_control::slotPowerState != power_control::SlotPowerState::off)
1271 {
1272 slotPowerLine.set_value(0);
1273
1274 if (!(slotPowerLine.get_value() > 0))
1275 {
1276 setSlotPowerState(SlotPowerState::off);
1277 setPowerState(PowerState::off);
1278 phosphor::logging::log<phosphor::logging::level::INFO>(
1279 "Slot Power is switched Off\n");
1280 }
1281 else
1282 {
1283 return -1;
1284 }
1285 }
1286 else
1287 {
1288 phosphor::logging::log<phosphor::logging::level::INFO>(
1289 "Slot Power is already in 'Off' state\n");
1290 return -1;
1291 }
1292 return 0;
1293}
1294static void slotPowerCycle()
1295{
1296 phosphor::logging::log<phosphor::logging::level::INFO>(
1297 "Slot Power Cycle started\n");
1298 slotPowerOff();
1299 slotPowerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001300 std::chrono::milliseconds(TimerMap["SlotPowerCycleMs"]));
Naveen Moses117c34e2021-05-26 20:10:51 +05301301 slotPowerCycleTimer.async_wait([](const boost::system::error_code ec) {
1302 if (ec)
1303 {
1304 if (ec != boost::asio::error::operation_aborted)
1305 {
1306 std::string errMsg =
1307 "Slot Power cycle timer async_wait failed: " + ec.message();
1308 phosphor::logging::log<phosphor::logging::level::ERR>(
1309 errMsg.c_str());
1310 }
1311 phosphor::logging::log<phosphor::logging::level::INFO>(
1312 "Slot Power cycle timer canceled\n");
1313 return;
1314 }
1315 phosphor::logging::log<phosphor::logging::level::INFO>(
1316 "Slot Power cycle timer completed\n");
1317 slotPowerOn();
1318 phosphor::logging::log<phosphor::logging::level::INFO>(
1319 "Slot Power Cycle Completed\n");
1320 });
1321}
1322#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001323static void gracefulPowerOff()
1324{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001325 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001326}
1327
1328static void forcePowerOff()
1329{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001330 if (assertGPIOForMs(powerOutConfig, TimerMap["ForceOffPulseMs"]) < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001331 {
1332 return;
1333 }
1334
Jason M. Billsc6961b62021-10-21 14:08:02 -07001335 // If the force off timer expires, then the power-button override failed
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001336 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1337 if (ec)
1338 {
1339 // operation_aborted is expected if timer is canceled before
1340 // completion.
1341 if (ec != boost::asio::error::operation_aborted)
1342 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001343 std::string errMsg =
1344 "Force power off async_wait failed: " + ec.message();
1345 phosphor::logging::log<phosphor::logging::level::ERR>(
1346 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001347 }
1348 return;
1349 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001350
1351 phosphor::logging::log<phosphor::logging::level::INFO>(
Jason M. Billsc6961b62021-10-21 14:08:02 -07001352 "Power-button override failed. Not sure what to do now.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001353 });
1354}
1355
1356static void reset()
1357{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001358 assertGPIOForMs(resetOutConfig, TimerMap["ResetPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001359}
1360
1361static void gracefulPowerOffTimerStart()
1362{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001363 phosphor::logging::log<phosphor::logging::level::INFO>(
1364 "Graceful power-off timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001365 gracefulPowerOffTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001366 std::chrono::seconds(TimerMap["GracefulPowerOffS"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001367 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1368 if (ec)
1369 {
1370 // operation_aborted is expected if timer is canceled before
1371 // completion.
1372 if (ec != boost::asio::error::operation_aborted)
1373 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001374 std::string errMsg =
1375 "Graceful power-off async_wait failed: " + ec.message();
1376 phosphor::logging::log<phosphor::logging::level::ERR>(
1377 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001378 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001379 phosphor::logging::log<phosphor::logging::level::INFO>(
1380 "Graceful power-off timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001381 return;
1382 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001383 phosphor::logging::log<phosphor::logging::level::INFO>(
1384 "Graceful power-off timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001385 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1386 });
1387}
1388
1389static void powerCycleTimerStart()
1390{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001391 phosphor::logging::log<phosphor::logging::level::INFO>(
1392 "Power-cycle timer started");
Priyatharshan P70120512020-09-16 18:47:20 +05301393 powerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001394 std::chrono::milliseconds(TimerMap["PowerCycleMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001395 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1396 if (ec)
1397 {
1398 // operation_aborted is expected if timer is canceled before
1399 // completion.
1400 if (ec != boost::asio::error::operation_aborted)
1401 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001402 std::string errMsg =
1403 "Power-cycle async_wait failed: " + ec.message();
1404 phosphor::logging::log<phosphor::logging::level::ERR>(
1405 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001406 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001407 phosphor::logging::log<phosphor::logging::level::INFO>(
1408 "Power-cycle timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001409 return;
1410 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001411 phosphor::logging::log<phosphor::logging::level::INFO>(
1412 "Power-cycle timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001413 sendPowerControlEvent(Event::powerCycleTimerExpired);
1414 });
1415}
1416
1417static void psPowerOKWatchdogTimerStart()
1418{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001419 phosphor::logging::log<phosphor::logging::level::INFO>(
1420 "power supply power OK watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001421 psPowerOKWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001422 std::chrono::milliseconds(TimerMap["PsPowerOKWatchdogMs"]));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001423 psPowerOKWatchdogTimer.async_wait([](const boost::system::error_code ec) {
1424 if (ec)
1425 {
1426 // operation_aborted is expected if timer is canceled before
1427 // completion.
1428 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001429 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001430 std::string errMsg =
1431 "power supply power OK watchdog async_wait failed: " +
1432 ec.message();
1433 phosphor::logging::log<phosphor::logging::level::ERR>(
1434 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001435 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001436 phosphor::logging::log<phosphor::logging::level::INFO>(
1437 "power supply power OK watchdog timer canceled");
1438 return;
1439 }
1440 phosphor::logging::log<phosphor::logging::level::INFO>(
1441 "power supply power OK watchdog timer expired");
1442 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1443 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001444}
1445
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001446static void warmResetCheckTimerStart()
1447{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001448 phosphor::logging::log<phosphor::logging::level::INFO>(
1449 "Warm reset check timer started");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001450 warmResetCheckTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001451 std::chrono::milliseconds(TimerMap["WarmResetCheckMs"]));
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001452 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1453 if (ec)
1454 {
1455 // operation_aborted is expected if timer is canceled before
1456 // completion.
1457 if (ec != boost::asio::error::operation_aborted)
1458 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001459 std::string errMsg =
1460 "Warm reset check async_wait failed: " + ec.message();
1461 phosphor::logging::log<phosphor::logging::level::ERR>(
1462 errMsg.c_str());
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001463 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001464 phosphor::logging::log<phosphor::logging::level::INFO>(
1465 "Warm reset check timer canceled");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001466 return;
1467 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001468 phosphor::logging::log<phosphor::logging::level::INFO>(
1469 "Warm reset check timer completed");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001470 sendPowerControlEvent(Event::warmResetDetected);
1471 });
1472}
1473
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001474static void pohCounterTimerStart()
1475{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001476 phosphor::logging::log<phosphor::logging::level::INFO>("POH timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001477 // Set the time-out as 1 hour, to align with POH command in ipmid
1478 pohCounterTimer.expires_after(std::chrono::hours(1));
1479 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1480 if (ec)
1481 {
1482 // operation_aborted is expected if timer is canceled before
1483 // completion.
1484 if (ec != boost::asio::error::operation_aborted)
1485 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001486 std::string errMsg =
1487 "POH timer async_wait failed: " + ec.message();
1488 phosphor::logging::log<phosphor::logging::level::ERR>(
1489 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001490 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001491 phosphor::logging::log<phosphor::logging::level::INFO>(
1492 "POH timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001493 return;
1494 }
1495
1496 if (getHostState(powerState) !=
1497 "xyz.openbmc_project.State.Host.HostState.Running")
1498 {
1499 return;
1500 }
1501
1502 conn->async_method_call(
1503 [](boost::system::error_code ec,
1504 const std::variant<uint32_t>& pohCounterProperty) {
1505 if (ec)
1506 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001507 phosphor::logging::log<phosphor::logging::level::INFO>(
1508 "error to get poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001509 return;
1510 }
1511 const uint32_t* pohCounter =
1512 std::get_if<uint32_t>(&pohCounterProperty);
1513 if (pohCounter == nullptr)
1514 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001515 phosphor::logging::log<phosphor::logging::level::INFO>(
1516 "unable to read poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001517 return;
1518 }
1519
1520 conn->async_method_call(
1521 [](boost::system::error_code ec) {
1522 if (ec)
1523 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001524 phosphor::logging::log<
1525 phosphor::logging::level::INFO>(
1526 "failed to set poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001527 }
1528 },
1529 "xyz.openbmc_project.Settings",
1530 "/xyz/openbmc_project/state/chassis0",
1531 "org.freedesktop.DBus.Properties", "Set",
1532 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1533 std::variant<uint32_t>(*pohCounter + 1));
1534 },
1535 "xyz.openbmc_project.Settings",
1536 "/xyz/openbmc_project/state/chassis0",
1537 "org.freedesktop.DBus.Properties", "Get",
1538 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1539
1540 pohCounterTimerStart();
1541 });
1542}
1543
1544static void currentHostStateMonitor()
1545{
Yong Li8d660212019-12-27 10:18:10 +08001546 if (getHostState(powerState) ==
1547 "xyz.openbmc_project.State.Host.HostState.Running")
1548 {
1549 pohCounterTimerStart();
1550 // Clear the restart cause set for the next restart
1551 clearRestartCause();
1552 }
1553 else
1554 {
1555 pohCounterTimer.cancel();
1556 // Set the restart cause set for this restart
1557 setRestartCause();
1558 }
1559
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001560 static auto match = sdbusplus::bus::match::match(
1561 *conn,
1562 "type='signal',member='PropertiesChanged', "
1563 "interface='org.freedesktop.DBus.Properties', "
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001564 "arg0='xyz.openbmc_project.State.Host'",
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001565 [](sdbusplus::message::message& message) {
1566 std::string intfName;
1567 std::map<std::string, std::variant<std::string>> properties;
1568
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001569 try
1570 {
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001571 message.read(intfName, properties);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001572 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05001573 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001574 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001575 phosphor::logging::log<phosphor::logging::level::ERR>(
1576 "Unable to read host state");
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001577 return;
1578 }
1579 if (properties.empty())
1580 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001581 phosphor::logging::log<phosphor::logging::level::ERR>(
1582 "ERROR: Empty PropertiesChanged signal received");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001583 return;
1584 }
1585
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001586 // We only want to check for CurrentHostState
1587 if (properties.begin()->first != "CurrentHostState")
1588 {
1589 return;
1590 }
1591 std::string* currentHostState =
1592 std::get_if<std::string>(&(properties.begin()->second));
1593 if (currentHostState == nullptr)
1594 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001595 std::string errMsg =
1596 properties.begin()->first + " property invalid";
1597 phosphor::logging::log<phosphor::logging::level::ERR>(
1598 errMsg.c_str());
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001599 return;
1600 }
1601
1602 if (*currentHostState ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001603 "xyz.openbmc_project.State.Host.HostState.Running")
1604 {
1605 pohCounterTimerStart();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001606 // Clear the restart cause set for the next restart
1607 clearRestartCause();
Yong Li8d660212019-12-27 10:18:10 +08001608 sd_journal_send("MESSAGE=Host system DC power is on",
1609 "PRIORITY=%i", LOG_INFO,
1610 "REDFISH_MESSAGE_ID=%s",
1611 "OpenBMC.0.1.DCPowerOn", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001612 }
1613 else
1614 {
1615 pohCounterTimer.cancel();
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301616 // POST_COMPLETE GPIO event is not working in some platforms
1617 // when power state is changed to OFF. This resulted in
1618 // 'OperatingSystemState' to stay at 'Standby', even though
1619 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1620 // if HostState is trurned to OFF.
1621 osIface->set_property("OperatingSystemState",
1622 std::string("Inactive"));
1623
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001624 // Set the restart cause set for this restart
1625 setRestartCause();
Rashmi RV89f61312020-01-22 15:41:50 +05301626 resetACBootProperty();
Yong Li8d660212019-12-27 10:18:10 +08001627 sd_journal_send("MESSAGE=Host system DC power is off",
1628 "PRIORITY=%i", LOG_INFO,
1629 "REDFISH_MESSAGE_ID=%s",
1630 "OpenBMC.0.1.DCPowerOff", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001631 }
1632 });
1633}
1634
1635static void sioPowerGoodWatchdogTimerStart()
1636{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001637 phosphor::logging::log<phosphor::logging::level::INFO>(
1638 "SIO power good watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001639 sioPowerGoodWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001640 std::chrono::milliseconds(TimerMap["SioPowerGoodWatchdogMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001641 sioPowerGoodWatchdogTimer.async_wait(
1642 [](const boost::system::error_code ec) {
1643 if (ec)
1644 {
1645 // operation_aborted is expected if timer is canceled before
1646 // completion.
1647 if (ec != boost::asio::error::operation_aborted)
1648 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001649 std::string errMsg =
1650 "SIO power good watchdog async_wait failed: " +
1651 ec.message();
1652 phosphor::logging::log<phosphor::logging::level::ERR>(
1653 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001654 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001655 phosphor::logging::log<phosphor::logging::level::INFO>(
1656 "SIO power good watchdog timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001657 return;
1658 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001659 phosphor::logging::log<phosphor::logging::level::INFO>(
1660 "SIO power good watchdog timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001661 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1662 });
1663}
1664
1665static void powerStateOn(const Event event)
1666{
1667 logEvent(__FUNCTION__, event);
1668 switch (event)
1669 {
1670 case Event::psPowerOKDeAssert:
1671 setPowerState(PowerState::off);
1672 // DC power is unexpectedly lost, beep
1673 beep(beepPowerFail);
1674 break;
1675 case Event::sioS5Assert:
1676 setPowerState(PowerState::transitionToOff);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001677 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001678 break;
Jason M. Billsfb957332021-01-28 13:18:46 -08001679#if USE_PLT_RST
1680 case Event::pltRstAssert:
1681#else
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001682 case Event::postCompleteDeAssert:
Jason M. Billsfb957332021-01-28 13:18:46 -08001683#endif
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001684 setPowerState(PowerState::checkForWarmReset);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001685 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001686 warmResetCheckTimerStart();
1687 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001688 case Event::powerButtonPressed:
1689 setPowerState(PowerState::gracefulTransitionToOff);
1690 gracefulPowerOffTimerStart();
1691 break;
1692 case Event::powerOffRequest:
1693 setPowerState(PowerState::transitionToOff);
1694 forcePowerOff();
1695 break;
1696 case Event::gracefulPowerOffRequest:
1697 setPowerState(PowerState::gracefulTransitionToOff);
1698 gracefulPowerOffTimerStart();
1699 gracefulPowerOff();
1700 break;
1701 case Event::powerCycleRequest:
1702 setPowerState(PowerState::transitionToCycleOff);
1703 forcePowerOff();
1704 break;
1705 case Event::gracefulPowerCycleRequest:
1706 setPowerState(PowerState::gracefulTransitionToCycleOff);
1707 gracefulPowerOffTimerStart();
1708 gracefulPowerOff();
1709 break;
1710 case Event::resetRequest:
1711 reset();
1712 break;
1713 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001714 phosphor::logging::log<phosphor::logging::level::INFO>(
1715 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001716 break;
1717 }
1718}
1719
1720static void powerStateWaitForPSPowerOK(const Event event)
1721{
1722 logEvent(__FUNCTION__, event);
1723 switch (event)
1724 {
1725 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301726 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001727 // Cancel any GPIO assertions held during the transition
1728 gpioAssertTimer.cancel();
1729 psPowerOKWatchdogTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301730 if (sioEnabled == true)
1731 {
1732 sioPowerGoodWatchdogTimerStart();
1733 setPowerState(PowerState::waitForSIOPowerGood);
1734 }
1735 else
1736 {
1737 setPowerState(PowerState::on);
1738 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001739 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301740 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001741 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001742 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001743 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001744 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001745 case Event::sioPowerGoodAssert:
1746 psPowerOKWatchdogTimer.cancel();
1747 setPowerState(PowerState::on);
1748 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001749 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001750 phosphor::logging::log<phosphor::logging::level::INFO>(
1751 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001752 break;
1753 }
1754}
1755
1756static void powerStateWaitForSIOPowerGood(const Event event)
1757{
1758 logEvent(__FUNCTION__, event);
1759 switch (event)
1760 {
1761 case Event::sioPowerGoodAssert:
1762 sioPowerGoodWatchdogTimer.cancel();
1763 setPowerState(PowerState::on);
1764 break;
1765 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001766 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001767 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001768 break;
1769 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001770 phosphor::logging::log<phosphor::logging::level::INFO>(
1771 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001772 break;
1773 }
1774}
1775
1776static void powerStateOff(const Event event)
1777{
1778 logEvent(__FUNCTION__, event);
1779 switch (event)
1780 {
1781 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301782 {
1783 if (sioEnabled == true)
1784 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001785 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301786 setPowerState(PowerState::waitForSIOPowerGood);
1787 }
1788 else
1789 {
1790 setPowerState(PowerState::on);
1791 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001792 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301793 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001794 case Event::sioS5DeAssert:
1795 setPowerState(PowerState::waitForPSPowerOK);
1796 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001797 case Event::sioPowerGoodAssert:
1798 setPowerState(PowerState::on);
1799 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001800 case Event::powerButtonPressed:
1801 psPowerOKWatchdogTimerStart();
1802 setPowerState(PowerState::waitForPSPowerOK);
1803 break;
1804 case Event::powerOnRequest:
1805 psPowerOKWatchdogTimerStart();
1806 setPowerState(PowerState::waitForPSPowerOK);
1807 powerOn();
1808 break;
1809 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001810 phosphor::logging::log<phosphor::logging::level::INFO>(
1811 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001812 break;
1813 }
1814}
1815
1816static void powerStateTransitionToOff(const Event event)
1817{
1818 logEvent(__FUNCTION__, event);
1819 switch (event)
1820 {
1821 case Event::psPowerOKDeAssert:
1822 // Cancel any GPIO assertions held during the transition
1823 gpioAssertTimer.cancel();
1824 setPowerState(PowerState::off);
1825 break;
1826 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001827 phosphor::logging::log<phosphor::logging::level::INFO>(
1828 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001829 break;
1830 }
1831}
1832
1833static void powerStateGracefulTransitionToOff(const Event event)
1834{
1835 logEvent(__FUNCTION__, event);
1836 switch (event)
1837 {
1838 case Event::psPowerOKDeAssert:
1839 gracefulPowerOffTimer.cancel();
1840 setPowerState(PowerState::off);
1841 break;
1842 case Event::gracefulPowerOffTimerExpired:
1843 setPowerState(PowerState::on);
1844 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001845 case Event::powerOffRequest:
1846 gracefulPowerOffTimer.cancel();
1847 setPowerState(PowerState::transitionToOff);
1848 forcePowerOff();
1849 break;
1850 case Event::powerCycleRequest:
1851 gracefulPowerOffTimer.cancel();
1852 setPowerState(PowerState::transitionToCycleOff);
1853 forcePowerOff();
1854 break;
1855 case Event::resetRequest:
1856 gracefulPowerOffTimer.cancel();
1857 setPowerState(PowerState::on);
1858 reset();
1859 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001860 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001861 phosphor::logging::log<phosphor::logging::level::INFO>(
1862 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001863 break;
1864 }
1865}
1866
1867static void powerStateCycleOff(const Event event)
1868{
1869 logEvent(__FUNCTION__, event);
1870 switch (event)
1871 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001872 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301873 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001874 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301875 if (sioEnabled == true)
1876 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001877 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301878 setPowerState(PowerState::waitForSIOPowerGood);
1879 }
1880 else
1881 {
1882 setPowerState(PowerState::on);
1883 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001884 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301885 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001886 case Event::sioS5DeAssert:
1887 powerCycleTimer.cancel();
1888 setPowerState(PowerState::waitForPSPowerOK);
1889 break;
1890 case Event::powerButtonPressed:
1891 powerCycleTimer.cancel();
1892 psPowerOKWatchdogTimerStart();
1893 setPowerState(PowerState::waitForPSPowerOK);
1894 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001895 case Event::powerCycleTimerExpired:
1896 psPowerOKWatchdogTimerStart();
1897 setPowerState(PowerState::waitForPSPowerOK);
1898 powerOn();
1899 break;
1900 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001901 phosphor::logging::log<phosphor::logging::level::INFO>(
1902 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001903 break;
1904 }
1905}
1906
1907static void powerStateTransitionToCycleOff(const Event event)
1908{
1909 logEvent(__FUNCTION__, event);
1910 switch (event)
1911 {
1912 case Event::psPowerOKDeAssert:
1913 // Cancel any GPIO assertions held during the transition
1914 gpioAssertTimer.cancel();
1915 setPowerState(PowerState::cycleOff);
1916 powerCycleTimerStart();
1917 break;
1918 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001919 phosphor::logging::log<phosphor::logging::level::INFO>(
1920 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001921 break;
1922 }
1923}
1924
1925static void powerStateGracefulTransitionToCycleOff(const Event event)
1926{
1927 logEvent(__FUNCTION__, event);
1928 switch (event)
1929 {
1930 case Event::psPowerOKDeAssert:
1931 gracefulPowerOffTimer.cancel();
1932 setPowerState(PowerState::cycleOff);
1933 powerCycleTimerStart();
1934 break;
1935 case Event::gracefulPowerOffTimerExpired:
1936 setPowerState(PowerState::on);
1937 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001938 case Event::powerOffRequest:
1939 gracefulPowerOffTimer.cancel();
1940 setPowerState(PowerState::transitionToOff);
1941 forcePowerOff();
1942 break;
1943 case Event::powerCycleRequest:
1944 gracefulPowerOffTimer.cancel();
1945 setPowerState(PowerState::transitionToCycleOff);
1946 forcePowerOff();
1947 break;
1948 case Event::resetRequest:
1949 gracefulPowerOffTimer.cancel();
1950 setPowerState(PowerState::on);
1951 reset();
1952 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001953 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001954 phosphor::logging::log<phosphor::logging::level::INFO>(
1955 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001956 break;
1957 }
1958}
1959
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001960static void powerStateCheckForWarmReset(const Event event)
1961{
1962 logEvent(__FUNCTION__, event);
1963 switch (event)
1964 {
1965 case Event::sioS5Assert:
1966 warmResetCheckTimer.cancel();
1967 setPowerState(PowerState::transitionToOff);
1968 break;
1969 case Event::warmResetDetected:
1970 setPowerState(PowerState::on);
1971 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001972 case Event::psPowerOKDeAssert:
1973 warmResetCheckTimer.cancel();
1974 setPowerState(PowerState::off);
1975 // DC power is unexpectedly lost, beep
1976 beep(beepPowerFail);
1977 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001978 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001979 phosphor::logging::log<phosphor::logging::level::INFO>(
1980 "No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001981 break;
1982 }
1983}
1984
Zev Weiss584aa132021-09-02 19:21:52 -05001985static void psPowerOKHandler(bool state)
1986{
1987 Event powerControlEvent =
1988 state ? Event::psPowerOKAssert : Event::psPowerOKDeAssert;
1989 sendPowerControlEvent(powerControlEvent);
1990}
1991
Zev Weiss584aa132021-09-02 19:21:52 -05001992static void sioPowerGoodHandler(bool state)
1993{
1994 Event powerControlEvent =
1995 state ? Event::sioPowerGoodAssert : Event::sioPowerGoodDeAssert;
1996 sendPowerControlEvent(powerControlEvent);
1997}
1998
Zev Weiss584aa132021-09-02 19:21:52 -05001999static void sioOnControlHandler(bool state)
2000{
2001 std::string logMsg =
2002 "SIO_ONCONTROL value changed: " + std::to_string(state);
2003 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
2004}
2005
Zev Weiss584aa132021-09-02 19:21:52 -05002006static void sioS5Handler(bool state)
2007{
2008 Event powerControlEvent = state ? Event::sioS5DeAssert : Event::sioS5Assert;
2009 sendPowerControlEvent(powerControlEvent);
2010}
2011
Zev Weiss584aa132021-09-02 19:21:52 -05002012static void powerButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002013{
Zev Weiss584aa132021-09-02 19:21:52 -05002014 powerButtonIface->set_property("ButtonPressed", !state);
2015 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002016 {
2017 powerButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002018 if (!powerButtonMask)
2019 {
2020 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002021 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002022 }
2023 else
2024 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002025 phosphor::logging::log<phosphor::logging::level::INFO>(
2026 "power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002027 }
2028 }
Zev Weiss584aa132021-09-02 19:21:52 -05002029}
2030
Zev Weiss584aa132021-09-02 19:21:52 -05002031static void resetButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002032{
Zev Weiss584aa132021-09-02 19:21:52 -05002033 resetButtonIface->set_property("ButtonPressed", !state);
2034 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002035 {
2036 resetButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002037 if (!resetButtonMask)
2038 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002039 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002040 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002041 }
2042 else
2043 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002044 phosphor::logging::log<phosphor::logging::level::INFO>(
2045 "reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002046 }
2047 }
Zev Weiss584aa132021-09-02 19:21:52 -05002048}
2049
Vijay Khemka04175c22020-10-09 14:28:11 -07002050#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002051static constexpr auto systemdBusname = "org.freedesktop.systemd1";
2052static constexpr auto systemdPath = "/org/freedesktop/systemd1";
2053static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
2054static constexpr auto systemTargetName = "chassis-system-reset.target";
2055
2056void systemReset()
2057{
2058 conn->async_method_call(
2059 [](boost::system::error_code ec) {
2060 if (ec)
2061 {
2062 phosphor::logging::log<phosphor::logging::level::ERR>(
2063 "Failed to call chassis system reset",
2064 phosphor::logging::entry("ERR=%s", ec.message().c_str()));
2065 }
2066 },
2067 systemdBusname, systemdPath, systemdInterface, "StartUnit",
2068 systemTargetName, "replace");
2069}
Vijay Khemka04175c22020-10-09 14:28:11 -07002070#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002071
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002072static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002073{
2074 conn->async_method_call(
2075 [](boost::system::error_code ec) {
2076 if (ec)
2077 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002078 phosphor::logging::log<phosphor::logging::level::INFO>(
2079 "failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002080 }
2081 },
Chen Yugang303bd582019-11-01 08:45:06 +08002082 "xyz.openbmc_project.Settings",
2083 "/xyz/openbmc_project/Chassis/Control/NMISource",
2084 "org.freedesktop.DBus.Properties", "Set",
2085 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
2086 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002087}
2088
2089static void nmiReset(void)
2090{
2091 static constexpr const uint8_t value = 1;
2092 const static constexpr int nmiOutPulseTimeMs = 200;
2093
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002094 phosphor::logging::log<phosphor::logging::level::INFO>("NMI out action");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002095 nmiOutLine.set_value(value);
Priyatharshan P70120512020-09-16 18:47:20 +05302096 std::string logMsg =
2097 nmiOutConfig.lineName + " set to " + std::to_string(value);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002098 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002099 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2100 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2101 // restore the NMI_OUT GPIO line back to the opposite value
2102 nmiOutLine.set_value(!value);
Priyatharshan P70120512020-09-16 18:47:20 +05302103 std::string logMsg = nmiOutConfig.lineName + " released";
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002104 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002105 if (ec)
2106 {
2107 // operation_aborted is expected if timer is canceled before
2108 // completion.
2109 if (ec != boost::asio::error::operation_aborted)
2110 {
Priyatharshan P70120512020-09-16 18:47:20 +05302111 std::string errMsg = nmiOutConfig.lineName +
2112 " async_wait failed: " + ec.message();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002113 phosphor::logging::log<phosphor::logging::level::ERR>(
2114 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002115 }
2116 }
2117 });
2118 // log to redfish
2119 nmiDiagIntLog();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002120 phosphor::logging::log<phosphor::logging::level::INFO>(
2121 "NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002122 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002123 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002124}
2125
2126static void nmiSourcePropertyMonitor(void)
2127{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002128 phosphor::logging::log<phosphor::logging::level::INFO>(
2129 "NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002130
2131 static std::unique_ptr<sdbusplus::bus::match::match> nmiSourceMatch =
2132 std::make_unique<sdbusplus::bus::match::match>(
2133 *conn,
2134 "type='signal',interface='org.freedesktop.DBus.Properties',"
Chen Yugang303bd582019-11-01 08:45:06 +08002135 "member='PropertiesChanged',arg0namespace='xyz.openbmc_project."
2136 "Chassis.Control."
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002137 "NMISource'",
2138 [](sdbusplus::message::message& msg) {
2139 std::string interfaceName;
2140 boost::container::flat_map<std::string,
2141 std::variant<bool, std::string>>
2142 propertiesChanged;
2143 std::string state;
2144 bool value = true;
2145 try
2146 {
2147 msg.read(interfaceName, propertiesChanged);
2148 if (propertiesChanged.begin()->first == "Enabled")
2149 {
2150 value =
2151 std::get<bool>(propertiesChanged.begin()->second);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002152 std::string logMsg =
2153 " NMI Enabled propertiesChanged value: " +
2154 std::to_string(value);
2155 phosphor::logging::log<phosphor::logging::level::INFO>(
2156 logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002157 nmiEnabled = value;
2158 if (nmiEnabled)
2159 {
2160 nmiReset();
2161 }
2162 }
2163 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002164 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002165 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002166 phosphor::logging::log<phosphor::logging::level::ERR>(
2167 "Unable to read NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002168 return;
2169 }
2170 });
2171}
2172
2173static void setNmiSource()
2174{
2175 conn->async_method_call(
2176 [](boost::system::error_code ec) {
2177 if (ec)
2178 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002179 phosphor::logging::log<phosphor::logging::level::ERR>(
2180 "failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002181 }
2182 },
Chen Yugang303bd582019-11-01 08:45:06 +08002183 "xyz.openbmc_project.Settings",
2184 "/xyz/openbmc_project/Chassis/Control/NMISource",
2185 "org.freedesktop.DBus.Properties", "Set",
2186 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
Jason M. Bills418ce112021-09-08 15:15:05 -07002187 std::variant<std::string>{
2188 "xyz.openbmc_project.Chassis.Control.NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002189 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002190 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002191}
2192
Zev Weiss584aa132021-09-02 19:21:52 -05002193static void nmiButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002194{
Zev Weiss584aa132021-09-02 19:21:52 -05002195 nmiButtonIface->set_property("ButtonPressed", !state);
2196 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002197 {
2198 nmiButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002199 if (nmiButtonMasked)
2200 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002201 phosphor::logging::log<phosphor::logging::level::INFO>(
2202 "NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002203 }
2204 else
2205 {
2206 setNmiSource();
2207 }
2208 }
Zev Weiss584aa132021-09-02 19:21:52 -05002209}
2210
Zev Weiss584aa132021-09-02 19:21:52 -05002211static void idButtonHandler(bool state)
2212{
2213 idButtonIface->set_property("ButtonPressed", !state);
2214}
2215
Jason M. Billsfb957332021-01-28 13:18:46 -08002216static void pltRstHandler(bool pltRst)
2217{
2218 if (pltRst)
2219 {
2220 sendPowerControlEvent(Event::pltRstDeAssert);
2221 }
2222 else
2223 {
2224 sendPowerControlEvent(Event::pltRstAssert);
2225 }
2226}
2227
Jason M. Bills9fd8ac22021-10-21 15:14:17 -07002228[[maybe_unused]] static void hostMiscHandler(sdbusplus::message::message& msg)
Jason M. Billsfb957332021-01-28 13:18:46 -08002229{
2230 std::string interfaceName;
2231 boost::container::flat_map<std::string, std::variant<bool>>
2232 propertiesChanged;
Jason M. Billsfb957332021-01-28 13:18:46 -08002233 try
2234 {
2235 msg.read(interfaceName, propertiesChanged);
2236 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002237 catch (const std::exception& e)
Jason M. Billsfb957332021-01-28 13:18:46 -08002238 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002239 phosphor::logging::log<phosphor::logging::level::ERR>(
2240 "Unable to read Host Misc status");
Jason M. Billsfb957332021-01-28 13:18:46 -08002241 return;
2242 }
2243 if (propertiesChanged.empty())
2244 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002245 phosphor::logging::log<phosphor::logging::level::ERR>(
2246 "ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002247 return;
2248 }
2249
2250 for (auto& [property, value] : propertiesChanged)
2251 {
2252 if (property == "ESpiPlatformReset")
2253 {
2254 bool* pltRst = std::get_if<bool>(&value);
2255 if (pltRst == nullptr)
2256 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002257 std::string errMsg = property + " property invalid";
2258 phosphor::logging::log<phosphor::logging::level::ERR>(
2259 errMsg.c_str());
Jason M. Billsfb957332021-01-28 13:18:46 -08002260 return;
2261 }
2262 pltRstHandler(*pltRst);
2263 }
2264 }
2265}
2266
Zev Weiss584aa132021-09-02 19:21:52 -05002267static void postCompleteHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002268{
Zev Weiss584aa132021-09-02 19:21:52 -05002269 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002270 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002271 sendPowerControlEvent(Event::postCompleteAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002272 osIface->set_property("OperatingSystemState", std::string("Standby"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002273 }
2274 else
2275 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002276 sendPowerControlEvent(Event::postCompleteDeAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002277 osIface->set_property("OperatingSystemState", std::string("Inactive"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002278 }
Zev Weiss584aa132021-09-02 19:21:52 -05002279}
2280
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302281static int loadConfigValues()
2282{
2283 const std::string configFilePath =
2284 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2285 ".json";
2286 std::ifstream configFile(configFilePath.c_str());
2287 if (!configFile.is_open())
2288 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002289 phosphor::logging::log<phosphor::logging::level::ERR>(
2290 "loadConfigValues : Cannot open config path");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302291 return -1;
2292 }
Zev Weiss1aa08b22021-09-15 17:06:20 -05002293 auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302294
Priyatharshan P70120512020-09-16 18:47:20 +05302295 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302296 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002297 phosphor::logging::log<phosphor::logging::level::ERR>(
2298 "Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302299 return -1;
2300 }
Priyatharshan P70120512020-09-16 18:47:20 +05302301 auto gpios = jsonData["gpio_configs"];
2302 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302303
Priyatharshan P70120512020-09-16 18:47:20 +05302304 ConfigData* tempGpioData;
2305
2306 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302307 {
Priyatharshan P70120512020-09-16 18:47:20 +05302308 if (!gpioConfig.contains("Name"))
2309 {
2310 phosphor::logging::log<phosphor::logging::level::ERR>(
2311 "The 'Name' field must be defined in Json file");
2312 return -1;
2313 }
2314
2315 // Iterate through the powersignal map to check if the gpio json config
2316 // entry is valid
2317 std::string gpioName = gpioConfig["Name"];
2318 auto signalMapIter = powerSignalMap.find(gpioName);
2319 if (signalMapIter == powerSignalMap.end())
2320 {
2321 std::string errMsg = "Undefined Name : " + gpioName;
2322 phosphor::logging::log<phosphor::logging::level::ERR>(
2323 errMsg.c_str());
2324 return -1;
2325 }
2326
2327 // assign the power signal name to the corresponding structure reference
2328 // from map then fillup the structure with coressponding json config
2329 // value
2330 tempGpioData = signalMapIter->second;
2331 tempGpioData->name = gpioName;
2332
2333 if (!gpioConfig.contains("Type"))
2334 {
2335 phosphor::logging::log<phosphor::logging::level::ERR>(
2336 "The \'Type\' field must be defined in Json file");
2337 return -1;
2338 }
2339
2340 std::string signalType = gpioConfig["Type"];
2341 if (signalType == "GPIO")
2342 {
2343 tempGpioData->type = ConfigType::GPIO;
2344 }
2345 else if (signalType == "DBUS")
2346 {
2347 tempGpioData->type = ConfigType::DBUS;
2348 }
2349 else
2350 {
2351 std::string errMsg = "Undefined Type : " + signalType;
2352 phosphor::logging::log<phosphor::logging::level::ERR>(
2353 errMsg.c_str());
2354 return -1;
2355 }
2356
2357 if (tempGpioData->type == ConfigType::GPIO)
2358 {
2359 if (gpioConfig.contains("LineName"))
2360 {
2361 tempGpioData->lineName = gpioConfig["LineName"];
2362 }
2363 else
2364 {
2365 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills418ce112021-09-08 15:15:05 -07002366 "The \'LineName\' field must be defined for GPIO configuration");
Priyatharshan P70120512020-09-16 18:47:20 +05302367 return -1;
2368 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002369 if (gpioConfig.contains("Polarity"))
2370 {
2371 std::string polarity = gpioConfig["Polarity"];
2372 if (polarity == "ActiveLow")
2373 {
2374 tempGpioData->polarity = false;
2375 }
2376 else if (polarity == "ActiveHigh")
2377 {
2378 tempGpioData->polarity = true;
2379 }
2380 else
2381 {
2382 std::string errMsg =
Jason M. Bills418ce112021-09-08 15:15:05 -07002383 "Polarity defined but not properly setup. Please only ActiveHigh or ActiveLow. Currently set to " +
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002384 polarity;
2385 phosphor::logging::log<phosphor::logging::level::ERR>(
2386 errMsg.c_str());
2387 return -1;
2388 }
2389 }
2390 else
2391 {
2392 std::string errMsg =
2393 "Polarity field not found for " + tempGpioData->lineName;
2394 phosphor::logging::log<phosphor::logging::level::ERR>(
2395 errMsg.c_str());
2396 return -1;
2397 }
Priyatharshan P70120512020-09-16 18:47:20 +05302398 }
2399 else
2400 {
2401 // if dbus based gpio config is defined read and update the dbus
2402 // params corresponding to the gpio config instance
2403 for (auto& [key, dbusParamName] : dbusParams)
2404 {
Logananth Sundararaja4308042021-10-20 11:52:05 +05302405 if (!gpioConfig.contains(dbusParamName))
Priyatharshan P70120512020-09-16 18:47:20 +05302406 {
2407 std::string errMsg =
2408 "The " + dbusParamName +
2409 "field must be defined for Dbus configuration ";
2410 phosphor::logging::log<phosphor::logging::level::ERR>(
2411 errMsg.c_str());
2412 return -1;
2413 }
2414 }
Logananth Sundararaja4308042021-10-20 11:52:05 +05302415 tempGpioData->dbusName =
2416 gpioConfig[dbusParams[DbusConfigType::name]];
2417 tempGpioData->path = gpioConfig[dbusParams[DbusConfigType::path]];
Priyatharshan P70120512020-09-16 18:47:20 +05302418 tempGpioData->interface =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302419 gpioConfig[dbusParams[DbusConfigType::interface]];
Priyatharshan P70120512020-09-16 18:47:20 +05302420 tempGpioData->lineName =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302421 gpioConfig[dbusParams[DbusConfigType::property]];
Priyatharshan P70120512020-09-16 18:47:20 +05302422 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302423 }
2424
Priyatharshan P70120512020-09-16 18:47:20 +05302425 // read and store the timer values from json config to Timer Map
2426 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302427 {
Priyatharshan P70120512020-09-16 18:47:20 +05302428 if (timers.contains(key.c_str()))
2429 {
2430 timerValue = timers[key.c_str()];
2431 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302432 }
2433
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302434 return 0;
2435}
Zev Weissa8f116a2021-09-01 21:08:30 -05002436
2437static bool getDbusMsgGPIOState(sdbusplus::message::message& msg,
2438 const std::string& lineName, bool& value)
2439{
2440 std::string thresholdInterface;
2441 std::string event;
2442 boost::container::flat_map<std::string, std::variant<bool>>
2443 propertiesChanged;
2444 try
2445 {
2446 msg.read(thresholdInterface, propertiesChanged);
2447 if (propertiesChanged.empty())
2448 {
2449 return false;
2450 }
2451
2452 event = propertiesChanged.begin()->first;
2453 if (event.empty() || event != lineName)
2454 {
2455 return false;
2456 }
2457
2458 value = std::get<bool>(propertiesChanged.begin()->second);
2459 return true;
2460 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002461 catch (const std::exception& e)
Zev Weissa8f116a2021-09-01 21:08:30 -05002462 {
2463 std::string logmsg =
2464 "exception while reading dbus property: " + lineName;
2465 phosphor::logging::log<phosphor::logging::level::ERR>(logmsg.c_str());
2466 return false;
2467 }
2468}
2469
2470static sdbusplus::bus::match::match
2471 dbusGPIOMatcher(const ConfigData& cfg, std::function<void(bool)> onMatch)
2472{
2473 auto pulseEventMatcherCallback =
2474 [&cfg, onMatch](sdbusplus::message::message& msg) {
2475 bool value = false;
2476 if (!getDbusMsgGPIOState(msg, cfg.lineName, value))
2477 {
2478 return;
2479 }
2480 onMatch(value);
2481 };
2482
2483 return sdbusplus::bus::match::match(
2484 static_cast<sdbusplus::bus::bus&>(*conn),
2485 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2486 "PropertiesChanged',arg0='" +
2487 cfg.dbusName + "'",
2488 std::move(pulseEventMatcherCallback));
2489}
2490
Priyatharshan P70120512020-09-16 18:47:20 +05302491int getProperty(ConfigData& configData)
2492{
2493 auto method = conn->new_method_call(
2494 configData.dbusName.c_str(), configData.path.c_str(),
2495 "org.freedesktop.DBus.Properties", "Get");
2496 method.append(configData.interface.c_str(), configData.lineName.c_str());
2497
2498 auto reply = conn->call(method);
2499 if (reply.is_method_error())
2500 {
2501 phosphor::logging::log<phosphor::logging::level::ERR>(
2502 "Error reading from Bus");
2503 return -1;
2504 }
2505 std::variant<int> resp;
2506 reply.read(resp);
2507 auto respValue = std::get_if<int>(&resp);
2508 if (!respValue)
2509 {
2510 phosphor::logging::log<phosphor::logging::level::ERR>(
2511 "Error reading response");
2512 return -1;
2513 }
2514 return (*respValue);
2515}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002516} // namespace power_control
2517
2518int main(int argc, char* argv[])
2519{
Lei YU92caa4c2021-02-23 16:59:25 +08002520 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05302521
2522 if (argc > 1)
2523 {
2524 node = argv[1];
2525 }
2526 std::string infoMsg =
2527 "Start Chassis power control service for host : " + node;
2528 phosphor::logging::log<phosphor::logging::level::INFO>(infoMsg.c_str());
2529
Lei YU92caa4c2021-02-23 16:59:25 +08002530 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002531
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302532 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08002533 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302534 {
Lei YU92caa4c2021-02-23 16:59:25 +08002535 std::string errMsg = "Host" + node + ": " + "Error in Parsing...";
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002536 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302537 }
Naveen Mosesec972d82021-07-16 21:19:23 +05302538 /* Currently for single host based systems additional busname is added
2539 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
2540 Going forward for single hosts the old bus name without zero numbering
2541 will be removed when all other applications adapted to the
2542 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
2543
2544 if (node == "0")
2545 {
2546 // Request all the dbus names
2547 conn->request_name(hostDbusName.c_str());
2548 conn->request_name(chassisDbusName.c_str());
2549 conn->request_name(osDbusName.c_str());
2550 conn->request_name(buttonDbusName.c_str());
2551 conn->request_name(nmiDbusName.c_str());
2552 conn->request_name(rstCauseDbusName.c_str());
2553 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302554
Zev Weissc4005bd2021-09-01 22:30:23 -05002555 hostDbusName += node;
2556 chassisDbusName += node;
2557 osDbusName += node;
2558 buttonDbusName += node;
2559 nmiDbusName += node;
2560 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002561
Priyatharshan P70120512020-09-16 18:47:20 +05302562 // Request all the dbus names
2563 conn->request_name(hostDbusName.c_str());
2564 conn->request_name(chassisDbusName.c_str());
2565 conn->request_name(osDbusName.c_str());
2566 conn->request_name(buttonDbusName.c_str());
2567 conn->request_name(nmiDbusName.c_str());
2568 conn->request_name(rstCauseDbusName.c_str());
2569
2570 if (sioPwrGoodConfig.lineName.empty() ||
2571 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05302572 {
Lei YU92caa4c2021-02-23 16:59:25 +08002573 sioEnabled = false;
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002574 phosphor::logging::log<phosphor::logging::level::INFO>(
2575 "SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05302576 }
2577
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002578 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302579 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002580 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002581 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302582 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302583 {
2584 return -1;
2585 }
2586 }
Priyatharshan P70120512020-09-16 18:47:20 +05302587 else if (powerOkConfig.type == ConfigType::DBUS)
2588 {
2589
2590 static sdbusplus::bus::match::match powerOkEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002591 power_control::dbusGPIOMatcher(powerOkConfig, psPowerOKHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302592 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302593 else
2594 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002595 phosphor::logging::log<phosphor::logging::level::ERR>(
2596 "PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002597 return -1;
2598 }
2599
Lei YU92caa4c2021-02-23 16:59:25 +08002600 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002601 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05302602 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302603 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302604 {
Priyatharshan P70120512020-09-16 18:47:20 +05302605 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002606 sioPowerGoodHandler, sioPowerGoodLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302607 sioPowerGoodEvent))
2608 {
2609 return -1;
2610 }
2611 }
2612 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
2613 {
2614 static sdbusplus::bus::match::match sioPwrGoodEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002615 power_control::dbusGPIOMatcher(sioPwrGoodConfig,
2616 sioPowerGoodHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302617 }
2618 else
2619 {
2620 phosphor::logging::log<phosphor::logging::level::ERR>(
2621 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302622 return -1;
2623 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002624
Priyatharshan P19c47a32020-08-12 18:16:43 +05302625 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302626 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302627 {
Priyatharshan P70120512020-09-16 18:47:20 +05302628 if (!requestGPIOEvents(sioOnControlConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002629 sioOnControlHandler, sioOnControlLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302630 sioOnControlEvent))
2631 {
2632 return -1;
2633 }
2634 }
2635 else if (sioOnControlConfig.type == ConfigType::DBUS)
2636 {
2637 static sdbusplus::bus::match::match sioOnControlEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002638 power_control::dbusGPIOMatcher(sioOnControlConfig,
2639 sioOnControlHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302640 }
2641 else
2642 {
2643 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills418ce112021-09-08 15:15:05 -07002644 "sioOnControl name should be configured from jsonconfig file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302645 return -1;
2646 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002647
Priyatharshan P19c47a32020-08-12 18:16:43 +05302648 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302649 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302650 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002651 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
Priyatharshan P70120512020-09-16 18:47:20 +05302652 sioS5Line, sioS5Event))
2653 {
2654 return -1;
2655 }
2656 }
2657 else if (sioS5Config.type == ConfigType::DBUS)
2658 {
2659 static sdbusplus::bus::match::match sioS5EventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002660 power_control::dbusGPIOMatcher(sioS5Config, sioS5Handler);
Priyatharshan P70120512020-09-16 18:47:20 +05302661 }
2662 else
2663 {
2664 phosphor::logging::log<phosphor::logging::level::ERR>(
2665 "sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302666 return -1;
2667 }
2668 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002669
2670 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302671 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002672 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002673 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
2674 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302675 {
2676 return -1;
2677 }
2678 }
Priyatharshan P70120512020-09-16 18:47:20 +05302679 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302680 {
Priyatharshan P70120512020-09-16 18:47:20 +05302681 static sdbusplus::bus::match::match powerButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002682 power_control::dbusGPIOMatcher(powerButtonConfig,
2683 powerButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002684 }
2685
2686 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302687 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002688 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002689 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
2690 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302691 {
2692 return -1;
2693 }
2694 }
Priyatharshan P70120512020-09-16 18:47:20 +05302695 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302696 {
Priyatharshan P70120512020-09-16 18:47:20 +05302697 static sdbusplus::bus::match::match resetButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002698 power_control::dbusGPIOMatcher(resetButtonConfig,
2699 resetButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002700 }
2701
2702 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302703 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302704 {
Priyatharshan P70120512020-09-16 18:47:20 +05302705 if (!nmiButtonConfig.lineName.empty())
2706 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002707 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302708 nmiButtonLine, nmiButtonEvent);
2709 }
2710 }
2711 else if (nmiButtonConfig.type == ConfigType::DBUS)
2712 {
2713 static sdbusplus::bus::match::match nmiButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002714 power_control::dbusGPIOMatcher(nmiButtonConfig, nmiButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302715 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002716
2717 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302718 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302719 {
Priyatharshan P70120512020-09-16 18:47:20 +05302720 if (!idButtonConfig.lineName.empty())
2721 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002722 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302723 idButtonLine, idButtonEvent);
2724 }
2725 }
2726 else if (idButtonConfig.type == ConfigType::DBUS)
2727 {
2728 static sdbusplus::bus::match::match idButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002729 power_control::dbusGPIOMatcher(idButtonConfig, idButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302730 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002731
Jason M. Billsfb957332021-01-28 13:18:46 -08002732#ifdef USE_PLT_RST
2733 sdbusplus::bus::match::match pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08002734 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08002735 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2736 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08002737 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08002738#endif
2739
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002740 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302741 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002742 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002743 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
2744 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302745 {
2746 return -1;
2747 }
2748 }
Priyatharshan P70120512020-09-16 18:47:20 +05302749 else if (postCompleteConfig.type == ConfigType::DBUS)
2750 {
2751 static sdbusplus::bus::match::match postCompleteEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002752 power_control::dbusGPIOMatcher(postCompleteConfig,
2753 postCompleteHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302754 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302755 else
2756 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002757 phosphor::logging::log<phosphor::logging::level::ERR>(
2758 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002759 return -1;
2760 }
2761
2762 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05302763 if (!nmiOutConfig.lineName.empty())
2764 {
2765 setGPIOOutput(nmiOutConfig.lineName, 0, nmiOutLine);
2766 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002767
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002768 // Initialize POWER_OUT and RESET_OUT GPIO.
2769 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05302770 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002771 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002772 if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
2773 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302774 {
2775 return -1;
2776 }
2777 }
2778 else
2779 {
2780 phosphor::logging::log<phosphor::logging::level::ERR>(
2781 "powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002782 return -1;
2783 }
2784
Priyatharshan P70120512020-09-16 18:47:20 +05302785 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002786 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002787 if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
2788 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302789 {
2790 return -1;
2791 }
2792 }
2793 else
2794 {
2795 phosphor::logging::log<phosphor::logging::level::ERR>(
2796 "ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002797 return -1;
2798 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002799 // Release line
2800 line.reset();
2801
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002802 // Initialize the power state
Lei YU92caa4c2021-02-23 16:59:25 +08002803 powerState = PowerState::off;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002804 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05302805
2806 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002807 {
Jean-Marie Verdun61b4a5b2021-09-19 08:53:28 -04002808 if (psPowerOKLine.get_value() > 0 ||
Lei YUa37c2472021-09-26 15:57:12 +08002809 (sioEnabled &&
2810 (sioPowerGoodLine.get_value() == sioPwrGoodConfig.polarity)))
Priyatharshan P70120512020-09-16 18:47:20 +05302811 {
2812 powerState = PowerState::on;
2813 }
2814 }
2815 else
2816 {
2817 if (getProperty(powerOkConfig))
2818 {
2819 powerState = PowerState::on;
2820 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002821 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002822 // Initialize the power state storage
Lei YU92caa4c2021-02-23 16:59:25 +08002823 if (initializePowerStateStorage() < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002824 {
2825 return -1;
2826 }
2827
2828 // Check if we need to start the Power Restore policy
Lei YU92caa4c2021-02-23 16:59:25 +08002829 powerRestorePolicyCheck();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002830
Lei YU92caa4c2021-02-23 16:59:25 +08002831 if (nmiOutLine)
2832 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002833
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002834 phosphor::logging::log<phosphor::logging::level::INFO>(
2835 "Initializing power state. ");
Lei YU92caa4c2021-02-23 16:59:25 +08002836 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002837
2838 // Power Control Service
2839 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002840 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002841
2842 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05302843 hostIface =
2844 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
2845 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002846 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08002847 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002848 "RequestedHostTransition",
2849 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2850 [](const std::string& requested, std::string& resp) {
2851 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2852 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002853 // if power button is masked, ignore this
2854 if (!powerButtonMask)
2855 {
2856 sendPowerControlEvent(Event::gracefulPowerOffRequest);
2857 addRestartCause(RestartCause::command);
2858 }
2859 else
2860 {
2861 phosphor::logging::log<phosphor::logging::level::INFO>(
2862 "Power Button Masked.");
2863 throw std::invalid_argument("Transition Request Masked");
2864 return 0;
2865 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002866 }
2867 else if (requested ==
2868 "xyz.openbmc_project.State.Host.Transition.On")
2869 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002870 // if power button is masked, ignore this
2871 if (!powerButtonMask)
2872 {
2873 sendPowerControlEvent(Event::powerOnRequest);
2874 addRestartCause(RestartCause::command);
2875 }
2876 else
2877 {
2878 phosphor::logging::log<phosphor::logging::level::INFO>(
2879 "Power Button Masked.");
2880 throw std::invalid_argument("Transition Request Masked");
2881 return 0;
2882 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002883 }
2884 else if (requested ==
2885 "xyz.openbmc_project.State.Host.Transition.Reboot")
2886 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002887 // if power button is masked, ignore this
2888 if (!powerButtonMask)
2889 {
2890 sendPowerControlEvent(Event::powerCycleRequest);
2891 addRestartCause(RestartCause::command);
2892 }
2893 else
2894 {
2895 phosphor::logging::log<phosphor::logging::level::INFO>(
2896 "Power Button Masked.");
2897 throw std::invalid_argument("Transition Request Masked");
2898 return 0;
2899 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002900 }
Jason M. Bills418ce112021-09-08 15:15:05 -07002901 else if (
2902 requested ==
2903 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot")
Jason M. Billse7520ba2020-01-31 11:19:03 -08002904 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002905 // if reset button is masked, ignore this
2906 if (!resetButtonMask)
2907 {
2908 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
2909 addRestartCause(RestartCause::command);
2910 }
2911 else
2912 {
2913 phosphor::logging::log<phosphor::logging::level::INFO>(
2914 "Reset Button Masked.");
2915 throw std::invalid_argument("Transition Request Masked");
2916 return 0;
2917 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002918 }
Jason M. Bills418ce112021-09-08 15:15:05 -07002919 else if (
2920 requested ==
2921 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot")
Jason M. Billse7520ba2020-01-31 11:19:03 -08002922 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002923 // if reset button is masked, ignore this
2924 if (!resetButtonMask)
2925 {
2926 sendPowerControlEvent(Event::resetRequest);
2927 addRestartCause(RestartCause::command);
2928 }
2929 else
2930 {
2931 phosphor::logging::log<phosphor::logging::level::INFO>(
2932 "Reset Button Masked.");
2933 throw std::invalid_argument("Transition Request Masked");
2934 return 0;
2935 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002936 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002937 else
2938 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002939 phosphor::logging::log<phosphor::logging::level::ERR>(
2940 "Unrecognized host state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002941 throw std::invalid_argument("Unrecognized Transition Request");
2942 return 0;
2943 }
2944 resp = requested;
2945 return 1;
2946 });
Lei YU92caa4c2021-02-23 16:59:25 +08002947 hostIface->register_property("CurrentHostState",
2948 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002949
Lei YU92caa4c2021-02-23 16:59:25 +08002950 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002951
2952 // Chassis Control Service
2953 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002954 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002955
2956 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002957 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05302958 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002959 "xyz.openbmc_project.State.Chassis");
2960
Lei YU92caa4c2021-02-23 16:59:25 +08002961 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002962 "RequestedPowerTransition",
2963 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
2964 [](const std::string& requested, std::string& resp) {
2965 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
2966 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002967 // if power button is masked, ignore this
2968 if (!powerButtonMask)
2969 {
2970 sendPowerControlEvent(Event::powerOffRequest);
2971 addRestartCause(RestartCause::command);
2972 }
2973 else
2974 {
2975 phosphor::logging::log<phosphor::logging::level::INFO>(
2976 "Power Button Masked.");
2977 throw std::invalid_argument("Transition Request Masked");
2978 return 0;
2979 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002980 }
2981 else if (requested ==
2982 "xyz.openbmc_project.State.Chassis.Transition.On")
2983 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002984 // if power button is masked, ignore this
2985 if (!powerButtonMask)
2986 {
2987 sendPowerControlEvent(Event::powerOnRequest);
2988 addRestartCause(RestartCause::command);
2989 }
2990 else
2991 {
2992 phosphor::logging::log<phosphor::logging::level::INFO>(
2993 "Power Button Masked.");
2994 throw std::invalid_argument("Transition Request Masked");
2995 return 0;
2996 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002997 }
2998 else if (requested ==
2999 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3000 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003001 // if power button is masked, ignore this
3002 if (!powerButtonMask)
3003 {
3004 sendPowerControlEvent(Event::powerCycleRequest);
3005 addRestartCause(RestartCause::command);
3006 }
3007 else
3008 {
3009 phosphor::logging::log<phosphor::logging::level::INFO>(
3010 "Power Button Masked.");
3011 throw std::invalid_argument("Transition Request Masked");
3012 return 0;
3013 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003014 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003015 else
3016 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003017 phosphor::logging::log<phosphor::logging::level::ERR>(
3018 "Unrecognized chassis state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003019 throw std::invalid_argument("Unrecognized Transition Request");
3020 return 0;
3021 }
3022 resp = requested;
3023 return 1;
3024 });
Lei YU92caa4c2021-02-23 16:59:25 +08003025 chassisIface->register_property("CurrentPowerState",
3026 std::string(getChassisState(powerState)));
3027 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003028
Lei YU92caa4c2021-02-23 16:59:25 +08003029 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003030
Vijay Khemka04175c22020-10-09 14:28:11 -07003031#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003032 // Chassis System Service
3033 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003034 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003035
3036 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003037 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003038 "/xyz/openbmc_project/state/chassis_system0",
3039 "xyz.openbmc_project.State.Chassis");
3040
Lei YU92caa4c2021-02-23 16:59:25 +08003041 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003042 "RequestedPowerTransition",
3043 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3044 [](const std::string& requested, std::string& resp) {
3045 if (requested ==
3046 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3047 {
Lei YU92caa4c2021-02-23 16:59:25 +08003048 systemReset();
3049 addRestartCause(RestartCause::command);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003050 }
3051 else
3052 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003053 phosphor::logging::log<phosphor::logging::level::ERR>(
3054 "Unrecognized chassis system state transition request.");
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003055 throw std::invalid_argument("Unrecognized Transition Request");
3056 return 0;
3057 }
3058 resp = requested;
3059 return 1;
3060 });
Lei YU92caa4c2021-02-23 16:59:25 +08003061 chassisSysIface->register_property(
3062 "CurrentPowerState", std::string(getChassisState(powerState)));
3063 chassisSysIface->register_property("LastStateChangeTime",
3064 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003065
Lei YU92caa4c2021-02-23 16:59:25 +08003066 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003067
Naveen Moses117c34e2021-05-26 20:10:51 +05303068 if (!slotPowerConfig.lineName.empty())
3069 {
3070 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3071 {
3072 return -1;
3073 }
3074
3075 slotPowerState = SlotPowerState::off;
3076 if (slotPowerLine.get_value() > 0)
3077 {
3078 slotPowerState = SlotPowerState::on;
3079 }
3080
3081 chassisSlotIface = chassisSysServer.add_interface(
3082 "/xyz/openbmc_project/state/chassis_system" + node,
3083 "xyz.openbmc_project.State.Chassis");
3084 chassisSlotIface->register_property(
3085 "RequestedPowerTransition",
3086 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3087 [](const std::string& requested, std::string& resp) {
3088 if (requested ==
3089 "xyz.openbmc_project.State.Chassis.Transition.On")
3090 {
3091 slotPowerOn();
3092 }
3093 else if (requested ==
3094 "xyz.openbmc_project.State.Chassis.Transition.Off")
3095 {
3096 slotPowerOff();
3097 }
Jason M. Bills418ce112021-09-08 15:15:05 -07003098 else if (
3099 requested ==
3100 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
Naveen Moses117c34e2021-05-26 20:10:51 +05303101 {
3102 slotPowerCycle();
3103 }
3104 else
3105 {
3106 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills418ce112021-09-08 15:15:05 -07003107 "Unrecognized chassis system state transition request.\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05303108 throw std::invalid_argument(
3109 "Unrecognized Transition Request");
3110 return 0;
3111 }
3112 resp = requested;
3113 return 1;
3114 });
3115 chassisSlotIface->register_property(
3116 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3117 chassisSlotIface->register_property("LastStateChangeTime",
3118 getCurrentTimeMs());
3119 chassisSlotIface->initialize();
3120 }
3121#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003122 // Buttons Service
3123 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003124 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003125
Priyatharshan P70120512020-09-16 18:47:20 +05303126 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003127 {
Priyatharshan P70120512020-09-16 18:47:20 +05303128 // Power Button Interface
3129 power_control::powerButtonIface = buttonsServer.add_interface(
3130 "/xyz/openbmc_project/chassis/buttons/power",
3131 "xyz.openbmc_project.Chassis.Buttons");
3132
3133 powerButtonIface->register_property(
3134 "ButtonMasked", false, [](const bool requested, bool& current) {
3135 if (requested)
3136 {
3137 if (powerButtonMask)
3138 {
3139 return 1;
3140 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003141 if (!setGPIOOutput(powerOutConfig.lineName,
3142 !powerOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303143 powerButtonMask))
3144 {
3145 throw std::runtime_error("Failed to request GPIO");
3146 return 0;
3147 }
3148 phosphor::logging::log<phosphor::logging::level::INFO>(
3149 "Power Button Masked.");
3150 }
3151 else
3152 {
3153 if (!powerButtonMask)
3154 {
3155 return 1;
3156 }
3157 phosphor::logging::log<phosphor::logging::level::INFO>(
3158 "Power Button Un-masked");
3159 powerButtonMask.reset();
3160 }
3161 // Update the mask setting
3162 current = requested;
3163 return 1;
3164 });
3165
3166 // Check power button state
3167 bool powerButtonPressed;
3168 if (powerButtonConfig.type == ConfigType::GPIO)
3169 {
3170 powerButtonPressed = powerButtonLine.get_value() == 0;
3171 }
3172 else
3173 {
3174 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3175 }
3176
3177 powerButtonIface->register_property("ButtonPressed",
3178 powerButtonPressed);
3179
3180 powerButtonIface->initialize();
3181 }
3182
3183 if (!resetButtonConfig.lineName.empty())
3184 {
3185 // Reset Button Interface
3186
Lei YU92caa4c2021-02-23 16:59:25 +08003187 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003188 "/xyz/openbmc_project/chassis/buttons/reset",
3189 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003190
Lei YU92caa4c2021-02-23 16:59:25 +08003191 resetButtonIface->register_property(
John Wang6c090072020-09-30 13:32:16 +08003192 "ButtonMasked", false, [](const bool requested, bool& current) {
3193 if (requested)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003194 {
Lei YU92caa4c2021-02-23 16:59:25 +08003195 if (resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003196 {
3197 return 1;
3198 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003199 if (!setGPIOOutput(resetOutConfig.lineName,
3200 !resetOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303201 resetButtonMask))
John Wang6c090072020-09-30 13:32:16 +08003202 {
3203 throw std::runtime_error("Failed to request GPIO");
3204 return 0;
3205 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003206 phosphor::logging::log<phosphor::logging::level::INFO>(
3207 "Reset Button Masked.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003208 }
John Wang6c090072020-09-30 13:32:16 +08003209 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003210 {
Lei YU92caa4c2021-02-23 16:59:25 +08003211 if (!resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003212 {
3213 return 1;
3214 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003215 phosphor::logging::log<phosphor::logging::level::INFO>(
3216 "Reset Button Un-masked");
Lei YU92caa4c2021-02-23 16:59:25 +08003217 resetButtonMask.reset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003218 }
John Wang6c090072020-09-30 13:32:16 +08003219 // Update the mask setting
3220 current = requested;
3221 return 1;
3222 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003223
John Wang6c090072020-09-30 13:32:16 +08003224 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303225 bool resetButtonPressed;
3226 if (resetButtonConfig.type == ConfigType::GPIO)
3227 {
3228 resetButtonPressed = resetButtonLine.get_value() == 0;
3229 }
3230 else
3231 {
3232 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3233 }
3234
Lei YU92caa4c2021-02-23 16:59:25 +08003235 resetButtonIface->register_property("ButtonPressed",
3236 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003237
Lei YU92caa4c2021-02-23 16:59:25 +08003238 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003239 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003240
Lei YU92caa4c2021-02-23 16:59:25 +08003241 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003242 {
3243 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003244 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003245 "/xyz/openbmc_project/chassis/buttons/nmi",
3246 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003247
Lei YU92caa4c2021-02-23 16:59:25 +08003248 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003249 "ButtonMasked", false, [](const bool requested, bool& current) {
Lei YU92caa4c2021-02-23 16:59:25 +08003250 if (nmiButtonMasked == requested)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003251 {
3252 // NMI button mask is already set as requested, so no change
3253 return 1;
3254 }
3255 if (requested)
3256 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003257 phosphor::logging::log<phosphor::logging::level::INFO>(
3258 "NMI Button Masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003259 nmiButtonMasked = true;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003260 }
3261 else
3262 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003263 phosphor::logging::log<phosphor::logging::level::INFO>(
3264 "NMI Button Un-masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003265 nmiButtonMasked = false;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003266 }
3267 // Update the mask setting
Lei YU92caa4c2021-02-23 16:59:25 +08003268 current = nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003269 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003270 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003271
Vijay Khemka33a532d2019-11-14 16:50:35 -08003272 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303273 bool nmiButtonPressed;
3274 if (nmiButtonConfig.type == ConfigType::GPIO)
3275 {
3276 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3277 }
3278 else
3279 {
3280 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3281 }
3282
Lei YU92caa4c2021-02-23 16:59:25 +08003283 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003284
Lei YU92caa4c2021-02-23 16:59:25 +08003285 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003286 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003287
Lei YU92caa4c2021-02-23 16:59:25 +08003288 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003289 {
3290 // NMI out Service
3291 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003292 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003293
Vijay Khemka33a532d2019-11-14 16:50:35 -08003294 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303295 nmiOutIface = nmiOutServer.add_interface(
3296 "/xyz/openbmc_project/control/host" + node + "/nmi",
3297 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003298 nmiOutIface->register_method("NMI", nmiReset);
3299 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003300 }
Chen Yugang174ec662019-08-19 19:58:49 +08003301
Lei YU92caa4c2021-02-23 16:59:25 +08003302 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003303 {
3304 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003305 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003306 "/xyz/openbmc_project/chassis/buttons/id",
3307 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003308
Vijay Khemka33a532d2019-11-14 16:50:35 -08003309 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303310 bool idButtonPressed;
3311 if (idButtonConfig.type == ConfigType::GPIO)
3312 {
3313 idButtonPressed = idButtonLine.get_value() == 0;
3314 }
3315 else
3316 {
3317 idButtonPressed = getProperty(idButtonConfig) == 0;
3318 }
3319
Lei YU92caa4c2021-02-23 16:59:25 +08003320 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003321
Lei YU92caa4c2021-02-23 16:59:25 +08003322 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003323 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003324
3325 // OS State Service
3326 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003327 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003328
3329 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003330 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003331 "/xyz/openbmc_project/state/os",
3332 "xyz.openbmc_project.State.OperatingSystem.Status");
3333
3334 // Get the initial OS state based on POST complete
3335 // 0: Asserted, OS state is "Standby" (ready to boot)
3336 // 1: De-Asserted, OS state is "Inactive"
Priyatharshan P70120512020-09-16 18:47:20 +05303337 std::string osState;
3338 if (postCompleteConfig.type == ConfigType::GPIO)
3339 {
3340 osState = postCompleteLine.get_value() > 0 ? "Inactive" : "Standby";
3341 }
3342 else
3343 {
3344 osState = getProperty(postCompleteConfig) > 0 ? "Inactive" : "Standby";
3345 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003346
Lei YU92caa4c2021-02-23 16:59:25 +08003347 osIface->register_property("OperatingSystemState", std::string(osState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003348
Lei YU92caa4c2021-02-23 16:59:25 +08003349 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003350
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003351 // Restart Cause Service
3352 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003353 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003354
3355 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003356 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303357 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003358 "xyz.openbmc_project.Control.Host.RestartCause");
3359
Lei YU92caa4c2021-02-23 16:59:25 +08003360 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003361 "RestartCause",
3362 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3363
Lei YU92caa4c2021-02-23 16:59:25 +08003364 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003365 "RequestedRestartCause",
3366 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3367 [](const std::string& requested, std::string& resp) {
3368 if (requested ==
3369 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3370 {
Lei YU92caa4c2021-02-23 16:59:25 +08003371 addRestartCause(RestartCause::watchdog);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003372 }
3373 else
3374 {
3375 throw std::invalid_argument(
3376 "Unrecognized RestartCause Request");
3377 return 0;
3378 }
3379
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003380 std::string logMsg = "RestartCause requested: " + requested;
3381 phosphor::logging::log<phosphor::logging::level::INFO>(
3382 logMsg.c_str());
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003383 resp = requested;
3384 return 1;
3385 });
3386
Lei YU92caa4c2021-02-23 16:59:25 +08003387 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003388
Lei YU92caa4c2021-02-23 16:59:25 +08003389 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003390
Lei YU92caa4c2021-02-23 16:59:25 +08003391 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003392
3393 return 0;
3394}