blob: ad603f7f1484d37c6138c57b087d8d7ea24153ca [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*/
16#include "i2c.hpp"
17
18#include <sys/sysinfo.h>
19#include <systemd/sd-journal.h>
20
21#include <boost/asio/posix/stream_descriptor.hpp>
22#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>
Vijay Khemkafc1ecc52020-04-01 10:49:28 -070025#include <phosphor-logging/log.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070026#include <sdbusplus/asio/object_server.hpp>
Vijay Khemka2b6f4422020-05-29 11:13:23 -070027
28#include <filesystem>
29#include <fstream>
30#include <iostream>
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;
37static std::shared_ptr<sdbusplus::asio::dbus_interface> hostIface;
38static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisIface;
Vijay Khemka75ad0cf2020-04-02 15:23:51 -070039static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSysIface;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070040static std::shared_ptr<sdbusplus::asio::dbus_interface> powerButtonIface;
41static std::shared_ptr<sdbusplus::asio::dbus_interface> resetButtonIface;
42static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiButtonIface;
43static std::shared_ptr<sdbusplus::asio::dbus_interface> osIface;
44static std::shared_ptr<sdbusplus::asio::dbus_interface> idButtonIface;
Chen Yugang174ec662019-08-19 19:58:49 +080045static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiOutIface;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -070046static std::shared_ptr<sdbusplus::asio::dbus_interface> restartCauseIface;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070047
48static gpiod::line powerButtonMask;
49static gpiod::line resetButtonMask;
50static bool nmiButtonMasked = false;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070051
52const static constexpr int powerPulseTimeMs = 200;
53const static constexpr int forceOffPulseTimeMs = 15000;
54const static constexpr int resetPulseTimeMs = 500;
Jason M. Billsfc9408a2020-01-31 14:54:17 -080055const static constexpr int powerCycleTimeMs = 5000;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070056const static constexpr int sioPowerGoodWatchdogTimeMs = 1000;
57const static constexpr int psPowerOKWatchdogTimeMs = 8000;
58const static constexpr int gracefulPowerOffTimeMs = 60000;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -070059const static constexpr int warmResetCheckTimeMs = 500;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070060const static constexpr int buttonMaskTimeMs = 60000;
61const static constexpr int powerOffSaveTimeMs = 7000;
62
63const static std::filesystem::path powerControlDir = "/var/lib/power-control";
64const static constexpr std::string_view powerStateFile = "power-state";
65
66static bool nmiEnabled = true;
67static constexpr const char* nmiOutName = "NMI_OUT";
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -070068static constexpr const char* powerOutName = "POWER_OUT";
69static constexpr const char* resetOutName = "RESET_OUT";
Ed Tanousf61ca6f2019-08-15 15:09:05 -070070
71// Timers
72// Time holding GPIOs asserted
73static boost::asio::steady_timer gpioAssertTimer(io);
74// Time between off and on during a power cycle
75static boost::asio::steady_timer powerCycleTimer(io);
76// Time OS gracefully powering off
77static boost::asio::steady_timer gracefulPowerOffTimer(io);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -070078// Time the warm reset check
79static boost::asio::steady_timer warmResetCheckTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -070080// Time power supply power OK assertion on power-on
81static boost::asio::steady_timer psPowerOKWatchdogTimer(io);
82// Time SIO power good assertion on power-on
83static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io);
84// Time power-off state save for power loss tracking
85static boost::asio::steady_timer powerStateSaveTimer(io);
86// POH timer
87static boost::asio::steady_timer pohCounterTimer(io);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -070088// Time when to allow restart cause updates
89static boost::asio::steady_timer restartCauseTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -070090
91// GPIO Lines and Event Descriptors
92static gpiod::line psPowerOKLine;
93static boost::asio::posix::stream_descriptor psPowerOKEvent(io);
94static gpiod::line sioPowerGoodLine;
95static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io);
96static gpiod::line sioOnControlLine;
97static boost::asio::posix::stream_descriptor sioOnControlEvent(io);
98static gpiod::line sioS5Line;
99static boost::asio::posix::stream_descriptor sioS5Event(io);
100static gpiod::line powerButtonLine;
101static boost::asio::posix::stream_descriptor powerButtonEvent(io);
102static gpiod::line resetButtonLine;
103static boost::asio::posix::stream_descriptor resetButtonEvent(io);
104static gpiod::line nmiButtonLine;
105static boost::asio::posix::stream_descriptor nmiButtonEvent(io);
106static gpiod::line idButtonLine;
107static boost::asio::posix::stream_descriptor idButtonEvent(io);
108static gpiod::line postCompleteLine;
109static boost::asio::posix::stream_descriptor postCompleteEvent(io);
110static gpiod::line nmiOutLine;
111
112static constexpr uint8_t beepPowerFail = 8;
113
114static void beep(const uint8_t& beepPriority)
115{
116 std::cerr << "Beep with priority: " << (unsigned)beepPriority << "\n";
117
118 conn->async_method_call(
119 [](boost::system::error_code ec) {
120 if (ec)
121 {
122 std::cerr << "beep returned error with "
123 "async_method_call (ec = "
124 << ec << ")\n";
125 return;
126 }
127 },
128 "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
129 "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
130}
131
132enum class PowerState
133{
134 on,
135 waitForPSPowerOK,
136 waitForSIOPowerGood,
137 failedTransitionToOn,
138 off,
139 transitionToOff,
140 gracefulTransitionToOff,
141 cycleOff,
142 transitionToCycleOff,
143 gracefulTransitionToCycleOff,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700144 checkForWarmReset,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700145};
146static PowerState powerState;
147static std::string getPowerStateName(PowerState state)
148{
149 switch (state)
150 {
151 case PowerState::on:
152 return "On";
153 break;
154 case PowerState::waitForPSPowerOK:
155 return "Wait for Power Supply Power OK";
156 break;
157 case PowerState::waitForSIOPowerGood:
158 return "Wait for SIO Power Good";
159 break;
160 case PowerState::failedTransitionToOn:
161 return "Failed Transition to On";
162 break;
163 case PowerState::off:
164 return "Off";
165 break;
166 case PowerState::transitionToOff:
167 return "Transition to Off";
168 break;
169 case PowerState::gracefulTransitionToOff:
170 return "Graceful Transition to Off";
171 break;
172 case PowerState::cycleOff:
173 return "Power Cycle Off";
174 break;
175 case PowerState::transitionToCycleOff:
176 return "Transition to Power Cycle Off";
177 break;
178 case PowerState::gracefulTransitionToCycleOff:
179 return "Graceful Transition to Power Cycle Off";
180 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700181 case PowerState::checkForWarmReset:
182 return "Check for Warm Reset";
183 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700184 default:
185 return "unknown state: " + std::to_string(static_cast<int>(state));
186 break;
187 }
188}
189static void logStateTransition(const PowerState state)
190{
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700191 std::string logMsg = "Moving to \"" + getPowerStateName(state) + "\" state";
192 phosphor::logging::log<phosphor::logging::level::INFO>(
193 logMsg.c_str(),
194 phosphor::logging::entry("STATE=%s", getPowerStateName(state).c_str()));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700195}
196
197enum class Event
198{
199 psPowerOKAssert,
200 psPowerOKDeAssert,
201 sioPowerGoodAssert,
202 sioPowerGoodDeAssert,
203 sioS5Assert,
204 sioS5DeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700205 postCompleteAssert,
206 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700207 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700208 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700209 powerCycleTimerExpired,
210 psPowerOKWatchdogTimerExpired,
211 sioPowerGoodWatchdogTimerExpired,
212 gracefulPowerOffTimerExpired,
213 powerOnRequest,
214 powerOffRequest,
215 powerCycleRequest,
216 resetRequest,
217 gracefulPowerOffRequest,
218 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700219 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700220};
221static std::string getEventName(Event event)
222{
223 switch (event)
224 {
225 case Event::psPowerOKAssert:
226 return "power supply power OK assert";
227 break;
228 case Event::psPowerOKDeAssert:
229 return "power supply power OK de-assert";
230 break;
231 case Event::sioPowerGoodAssert:
232 return "SIO power good assert";
233 break;
234 case Event::sioPowerGoodDeAssert:
235 return "SIO power good de-assert";
236 break;
237 case Event::sioS5Assert:
238 return "SIO S5 assert";
239 break;
240 case Event::sioS5DeAssert:
241 return "SIO S5 de-assert";
242 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700243 case Event::postCompleteAssert:
244 return "POST Complete assert";
245 break;
246 case Event::postCompleteDeAssert:
247 return "POST Complete de-assert";
248 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700249 case Event::powerButtonPressed:
250 return "power button pressed";
251 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700252 case Event::resetButtonPressed:
253 return "reset button pressed";
254 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700255 case Event::powerCycleTimerExpired:
256 return "power cycle timer expired";
257 break;
258 case Event::psPowerOKWatchdogTimerExpired:
259 return "power supply power OK watchdog timer expired";
260 break;
261 case Event::sioPowerGoodWatchdogTimerExpired:
262 return "SIO power good watchdog timer expired";
263 break;
264 case Event::gracefulPowerOffTimerExpired:
265 return "graceful power-off timer expired";
266 break;
267 case Event::powerOnRequest:
268 return "power-on request";
269 break;
270 case Event::powerOffRequest:
271 return "power-off request";
272 break;
273 case Event::powerCycleRequest:
274 return "power-cycle request";
275 break;
276 case Event::resetRequest:
277 return "reset request";
278 break;
279 case Event::gracefulPowerOffRequest:
280 return "graceful power-off request";
281 break;
282 case Event::gracefulPowerCycleRequest:
283 return "graceful power-cycle request";
284 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700285 case Event::warmResetDetected:
286 return "warm reset detected";
287 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700288 default:
289 return "unknown event: " + std::to_string(static_cast<int>(event));
290 break;
291 }
292}
293static void logEvent(const std::string_view stateHandler, const Event event)
294{
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700295 std::string logMsg{stateHandler};
296 logMsg += ": " + getEventName(event) + " event received";
297 phosphor::logging::log<phosphor::logging::level::INFO>(
298 logMsg.c_str(),
299 phosphor::logging::entry("EVENT=%s", getEventName(event).c_str()));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700300}
301
302// Power state handlers
303static void powerStateOn(const Event event);
304static void powerStateWaitForPSPowerOK(const Event event);
305static void powerStateWaitForSIOPowerGood(const Event event);
306static void powerStateFailedTransitionToOn(const Event event);
307static void powerStateOff(const Event event);
308static void powerStateTransitionToOff(const Event event);
309static void powerStateGracefulTransitionToOff(const Event event);
310static void powerStateCycleOff(const Event event);
311static void powerStateTransitionToCycleOff(const Event event);
312static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700313static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700314
315static std::function<void(const Event)> getPowerStateHandler(PowerState state)
316{
317 switch (state)
318 {
319 case PowerState::on:
320 return powerStateOn;
321 break;
322 case PowerState::waitForPSPowerOK:
323 return powerStateWaitForPSPowerOK;
324 break;
325 case PowerState::waitForSIOPowerGood:
326 return powerStateWaitForSIOPowerGood;
327 break;
328 case PowerState::failedTransitionToOn:
329 return powerStateFailedTransitionToOn;
330 break;
331 case PowerState::off:
332 return powerStateOff;
333 break;
334 case PowerState::transitionToOff:
335 return powerStateTransitionToOff;
336 break;
337 case PowerState::gracefulTransitionToOff:
338 return powerStateGracefulTransitionToOff;
339 break;
340 case PowerState::cycleOff:
341 return powerStateCycleOff;
342 break;
343 case PowerState::transitionToCycleOff:
344 return powerStateTransitionToCycleOff;
345 break;
346 case PowerState::gracefulTransitionToCycleOff:
347 return powerStateGracefulTransitionToCycleOff;
348 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700349 case PowerState::checkForWarmReset:
350 return powerStateCheckForWarmReset;
351 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700352 default:
353 return std::function<void(const Event)>{};
354 break;
355 }
356};
357
358static void sendPowerControlEvent(const Event event)
359{
360 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
361 if (handler == nullptr)
362 {
363 std::cerr << "Failed to find handler for power state: "
364 << static_cast<int>(powerState) << "\n";
365 return;
366 }
367 handler(event);
368}
369
370static uint64_t getCurrentTimeMs()
371{
372 struct timespec time = {};
373
374 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
375 {
376 return 0;
377 }
378 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
379 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
380
381 return currentTimeMs;
382}
383
384static constexpr std::string_view getHostState(const PowerState state)
385{
386 switch (state)
387 {
388 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700389 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700390 case PowerState::gracefulTransitionToCycleOff:
391 return "xyz.openbmc_project.State.Host.HostState.Running";
392 break;
393 case PowerState::waitForPSPowerOK:
394 case PowerState::waitForSIOPowerGood:
395 case PowerState::failedTransitionToOn:
396 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700397 case PowerState::transitionToOff:
398 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700399 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700400 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700401 return "xyz.openbmc_project.State.Host.HostState.Off";
402 break;
403 default:
404 return "";
405 break;
406 }
407};
408static constexpr std::string_view getChassisState(const PowerState state)
409{
410 switch (state)
411 {
412 case PowerState::on:
413 case PowerState::transitionToOff:
414 case PowerState::gracefulTransitionToOff:
415 case PowerState::transitionToCycleOff:
416 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700417 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700418 return "xyz.openbmc_project.State.Chassis.PowerState.On";
419 break;
420 case PowerState::waitForPSPowerOK:
421 case PowerState::waitForSIOPowerGood:
422 case PowerState::failedTransitionToOn:
423 case PowerState::off:
424 case PowerState::cycleOff:
425 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
426 break;
427 default:
428 return "";
429 break;
430 }
431};
432static void savePowerState(const PowerState state)
433{
434 powerStateSaveTimer.expires_after(
435 std::chrono::milliseconds(powerOffSaveTimeMs));
436 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
437 if (ec)
438 {
439 // operation_aborted is expected if timer is canceled before
440 // completion.
441 if (ec != boost::asio::error::operation_aborted)
442 {
443 std::cerr << "Power-state save async_wait failed: "
444 << ec.message() << "\n";
445 }
446 return;
447 }
448 std::ofstream powerStateStream(powerControlDir / powerStateFile);
449 powerStateStream << getChassisState(state);
450 });
451}
452static void setPowerState(const PowerState state)
453{
454 powerState = state;
455 logStateTransition(state);
456
457 hostIface->set_property("CurrentHostState",
458 std::string(getHostState(powerState)));
459
460 chassisIface->set_property("CurrentPowerState",
461 std::string(getChassisState(powerState)));
462 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
463
464 // Save the power state for the restore policy
465 savePowerState(state);
466}
467
468enum class RestartCause
469{
470 command,
471 resetButton,
472 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700473 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700474 powerPolicyOn,
475 powerPolicyRestore,
476 softReset,
477};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700478static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700479static std::string getRestartCause(RestartCause cause)
480{
481 switch (cause)
482 {
483 case RestartCause::command:
484 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
485 break;
486 case RestartCause::resetButton:
487 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
488 break;
489 case RestartCause::powerButton:
490 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
491 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700492 case RestartCause::watchdog:
493 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
494 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700495 case RestartCause::powerPolicyOn:
496 return "xyz.openbmc_project.State.Host.RestartCause."
497 "PowerPolicyAlwaysOn";
498 break;
499 case RestartCause::powerPolicyRestore:
500 return "xyz.openbmc_project.State.Host.RestartCause."
501 "PowerPolicyPreviousState";
502 break;
503 case RestartCause::softReset:
504 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
505 break;
506 default:
507 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
508 break;
509 }
510}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700511static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700512{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700513 // Add this to the set of causes for this restart
514 causeSet.insert(cause);
515}
516static void clearRestartCause()
517{
518 // Clear the set for the next restart
519 causeSet.clear();
520}
521static void setRestartCauseProperty(const std::string& cause)
522{
523 std::cerr << "RestartCause set to " << cause << "\n";
524 restartCauseIface->set_property("RestartCause", cause);
525}
Rashmi RV89f61312020-01-22 15:41:50 +0530526
527static void resetACBootProperty()
528{
529 if ((causeSet.contains(RestartCause::command)) ||
530 (causeSet.contains(RestartCause::softReset)))
531 {
532 conn->async_method_call(
533 [](boost::system::error_code ec) {
534 if (ec)
535 {
536 std::cerr << "failed to reset ACBoot property\n";
537 }
538 },
539 "xyz.openbmc_project.Settings",
540 "/xyz/openbmc_project/control/host0/ac_boot",
541 "org.freedesktop.DBus.Properties", "Set",
542 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
543 std::variant<std::string>{"False"});
544 }
545}
546
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700547static void setRestartCause()
548{
549 // Determine the actual restart cause based on the set of causes
550 std::string restartCause =
551 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
552 if (causeSet.contains(RestartCause::watchdog))
553 {
554 restartCause = getRestartCause(RestartCause::watchdog);
555 }
556 else if (causeSet.contains(RestartCause::command))
557 {
558 restartCause = getRestartCause(RestartCause::command);
559 }
560 else if (causeSet.contains(RestartCause::resetButton))
561 {
562 restartCause = getRestartCause(RestartCause::resetButton);
563 }
564 else if (causeSet.contains(RestartCause::powerButton))
565 {
566 restartCause = getRestartCause(RestartCause::powerButton);
567 }
568 else if (causeSet.contains(RestartCause::powerPolicyOn))
569 {
570 restartCause = getRestartCause(RestartCause::powerPolicyOn);
571 }
572 else if (causeSet.contains(RestartCause::powerPolicyRestore))
573 {
574 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
575 }
576 else if (causeSet.contains(RestartCause::softReset))
577 {
578 restartCause = getRestartCause(RestartCause::softReset);
579 }
580
581 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700582}
583
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700584static void systemPowerGoodFailedLog()
585{
586 sd_journal_send(
587 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
588 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
589 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
590 sioPowerGoodWatchdogTimeMs, NULL);
591}
592
593static void psPowerOKFailedLog()
594{
595 sd_journal_send(
596 "MESSAGE=PowerControl: power supply power good failed to assert",
597 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
598 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
599 psPowerOKWatchdogTimeMs, NULL);
600}
601
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700602static void powerRestorePolicyLog()
603{
604 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
605 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
606 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
607}
608
609static void powerButtonPressLog()
610{
611 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
612 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
613 "OpenBMC.0.1.PowerButtonPressed", NULL);
614}
615
616static void resetButtonPressLog()
617{
618 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
619 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
620 "OpenBMC.0.1.ResetButtonPressed", NULL);
621}
622
623static void nmiButtonPressLog()
624{
625 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
626 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
627 "OpenBMC.0.1.NMIButtonPressed", NULL);
628}
629
630static void nmiDiagIntLog()
631{
632 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
633 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
634 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
635}
636
637static int initializePowerStateStorage()
638{
639 // create the power control directory if it doesn't exist
640 std::error_code ec;
641 if (!(std::filesystem::create_directories(powerControlDir, ec)))
642 {
643 if (ec.value() != 0)
644 {
645 std::cerr << "failed to create " << powerControlDir << ": "
646 << ec.message() << "\n";
647 return -1;
648 }
649 }
650 // Create the power state file if it doesn't exist
651 if (!std::filesystem::exists(powerControlDir / powerStateFile))
652 {
653 std::ofstream powerStateStream(powerControlDir / powerStateFile);
654 powerStateStream << getChassisState(powerState);
655 }
656 return 0;
657}
658
659static bool wasPowerDropped()
660{
661 std::ifstream powerStateStream(powerControlDir / powerStateFile);
662 if (!powerStateStream.is_open())
663 {
664 std::cerr << "Failed to open power state file\n";
665 return false;
666 }
667
668 std::string state;
669 std::getline(powerStateStream, state);
670 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
671}
672
673static void invokePowerRestorePolicy(const std::string& policy)
674{
675 // Async events may call this twice, but we only want to run once
676 static bool policyInvoked = false;
677 if (policyInvoked)
678 {
679 return;
680 }
681 policyInvoked = true;
682
683 std::cerr << "Power restore delay expired, invoking " << policy << "\n";
684 if (policy ==
685 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
686 {
687 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700688 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700689 }
690 else if (policy == "xyz.openbmc_project.Control.Power.RestorePolicy."
691 "Policy.Restore")
692 {
693 if (wasPowerDropped())
694 {
695 std::cerr << "Power was dropped, restoring Host On state\n";
696 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700697 setRestartCauseProperty(
698 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700699 }
700 else
701 {
702 std::cerr << "No power drop, restoring Host Off state\n";
703 }
704 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -0700705 // We're done with the previous power state for the restore policy, so store
706 // the current state
707 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700708}
709
710static void powerRestorePolicyDelay(int delay)
711{
712 // Async events may call this twice, but we only want to run once
713 static bool delayStarted = false;
714 if (delayStarted)
715 {
716 return;
717 }
718 delayStarted = true;
719 // Calculate the delay from now to meet the requested delay
720 // Subtract the approximate uboot time
721 static constexpr const int ubootSeconds = 20;
722 delay -= ubootSeconds;
723 // Subtract the time since boot
724 struct sysinfo info = {};
725 if (sysinfo(&info) == 0)
726 {
727 delay -= info.uptime;
728 }
729 // 0 is the minimum delay
730 delay = std::max(delay, 0);
731
732 static boost::asio::steady_timer powerRestorePolicyTimer(io);
733 powerRestorePolicyTimer.expires_after(std::chrono::seconds(delay));
734 std::cerr << "Power restore delay of " << delay << " seconds started\n";
735 powerRestorePolicyTimer.async_wait([](const boost::system::error_code ec) {
736 if (ec)
737 {
738 // operation_aborted is expected if timer is canceled before
739 // completion.
740 if (ec != boost::asio::error::operation_aborted)
741 {
742 std::cerr << "power restore policy async_wait failed: "
743 << ec.message() << "\n";
744 }
745 return;
746 }
747 // Get Power Restore Policy
748 // In case PowerRestorePolicy is not available, set a match for it
749 static std::unique_ptr<sdbusplus::bus::match::match>
750 powerRestorePolicyMatch = std::make_unique<
751 sdbusplus::bus::match::match>(
752 *conn,
753 "type='signal',interface='org.freedesktop.DBus.Properties',"
754 "member='PropertiesChanged',arg0namespace='xyz.openbmc_"
755 "project.Control.Power.RestorePolicy'",
756 [](sdbusplus::message::message& msg) {
757 std::string interfaceName;
758 boost::container::flat_map<std::string,
759 std::variant<std::string>>
760 propertiesChanged;
761 std::string policy;
762 try
763 {
764 msg.read(interfaceName, propertiesChanged);
765 policy = std::get<std::string>(
766 propertiesChanged.begin()->second);
767 }
768 catch (std::exception& e)
769 {
770 std::cerr
771 << "Unable to read power restore policy value\n";
772 powerRestorePolicyMatch.reset();
773 return;
774 }
775 invokePowerRestorePolicy(policy);
776 powerRestorePolicyMatch.reset();
777 });
778
779 // Check if it's already on DBus
780 conn->async_method_call(
781 [](boost::system::error_code ec,
782 const std::variant<std::string>& policyProperty) {
783 if (ec)
784 {
785 return;
786 }
787 powerRestorePolicyMatch.reset();
788 const std::string* policy =
789 std::get_if<std::string>(&policyProperty);
790 if (policy == nullptr)
791 {
792 std::cerr << "Unable to read power restore policy value\n";
793 return;
794 }
795 invokePowerRestorePolicy(*policy);
796 },
797 "xyz.openbmc_project.Settings",
798 "/xyz/openbmc_project/control/host0/power_restore_policy",
799 "org.freedesktop.DBus.Properties", "Get",
800 "xyz.openbmc_project.Control.Power.RestorePolicy",
801 "PowerRestorePolicy");
802 });
803}
804
805static void powerRestorePolicyStart()
806{
807 std::cerr << "Power restore policy started\n";
808 powerRestorePolicyLog();
809
810 // Get the desired delay time
811 // In case PowerRestoreDelay is not available, set a match for it
812 static std::unique_ptr<sdbusplus::bus::match::match>
813 powerRestoreDelayMatch = std::make_unique<sdbusplus::bus::match::match>(
814 *conn,
815 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
816 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Control."
817 "Power.RestoreDelay'",
818 [](sdbusplus::message::message& msg) {
819 std::string interfaceName;
820 boost::container::flat_map<std::string, std::variant<uint16_t>>
821 propertiesChanged;
822 int delay = 0;
823 try
824 {
825 msg.read(interfaceName, propertiesChanged);
826 delay =
827 std::get<uint16_t>(propertiesChanged.begin()->second);
828 }
829 catch (std::exception& e)
830 {
831 std::cerr << "Unable to read power restore delay value\n";
832 powerRestoreDelayMatch.reset();
833 return;
834 }
835 powerRestorePolicyDelay(delay);
836 powerRestoreDelayMatch.reset();
837 });
838
839 // Check if it's already on DBus
840 conn->async_method_call(
841 [](boost::system::error_code ec,
842 const std::variant<uint16_t>& delayProperty) {
843 if (ec)
844 {
845 return;
846 }
847 powerRestoreDelayMatch.reset();
848 const uint16_t* delay = std::get_if<uint16_t>(&delayProperty);
849 if (delay == nullptr)
850 {
851 std::cerr << "Unable to read power restore delay value\n";
852 return;
853 }
854 powerRestorePolicyDelay(*delay);
855 },
856 "xyz.openbmc_project.Settings",
857 "/xyz/openbmc_project/control/power_restore_delay",
858 "org.freedesktop.DBus.Properties", "Get",
859 "xyz.openbmc_project.Control.Power.RestoreDelay", "PowerRestoreDelay");
860}
861
862static void powerRestorePolicyCheck()
863{
864 // In case ACBoot is not available, set a match for it
865 static std::unique_ptr<sdbusplus::bus::match::match> acBootMatch =
866 std::make_unique<sdbusplus::bus::match::match>(
867 *conn,
868 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
869 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Common."
870 "ACBoot'",
871 [](sdbusplus::message::message& msg) {
872 std::string interfaceName;
873 boost::container::flat_map<std::string,
874 std::variant<std::string>>
875 propertiesChanged;
876 std::string acBoot;
877 try
878 {
879 msg.read(interfaceName, propertiesChanged);
880 acBoot = std::get<std::string>(
881 propertiesChanged.begin()->second);
882 }
883 catch (std::exception& e)
884 {
885 std::cerr << "Unable to read AC Boot status\n";
886 acBootMatch.reset();
887 return;
888 }
889 if (acBoot == "Unknown")
890 {
891 return;
892 }
893 if (acBoot == "True")
894 {
895 // Start the Power Restore policy
896 powerRestorePolicyStart();
897 }
898 acBootMatch.reset();
899 });
900
901 // Check if it's already on DBus
902 conn->async_method_call(
903 [](boost::system::error_code ec,
904 const std::variant<std::string>& acBootProperty) {
905 if (ec)
906 {
907 return;
908 }
909 const std::string* acBoot =
910 std::get_if<std::string>(&acBootProperty);
911 if (acBoot == nullptr)
912 {
913 std::cerr << "Unable to read AC Boot status\n";
914 return;
915 }
916 if (*acBoot == "Unknown")
917 {
918 return;
919 }
920 if (*acBoot == "True")
921 {
922 // Start the Power Restore policy
923 powerRestorePolicyStart();
924 }
925 acBootMatch.reset();
926 },
927 "xyz.openbmc_project.Settings",
928 "/xyz/openbmc_project/control/host0/ac_boot",
929 "org.freedesktop.DBus.Properties", "Get",
930 "xyz.openbmc_project.Common.ACBoot", "ACBoot");
931}
932
933static bool requestGPIOEvents(
934 const std::string& name, const std::function<void()>& handler,
935 gpiod::line& gpioLine,
936 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
937{
938 // Find the GPIO line
939 gpioLine = gpiod::find_line(name);
940 if (!gpioLine)
941 {
942 std::cerr << "Failed to find the " << name << " line\n";
943 return false;
944 }
945
946 try
947 {
948 gpioLine.request(
949 {"power-control", gpiod::line_request::EVENT_BOTH_EDGES});
950 }
951 catch (std::exception&)
952 {
953 std::cerr << "Failed to request events for " << name << "\n";
954 return false;
955 }
956
957 int gpioLineFd = gpioLine.event_get_fd();
958 if (gpioLineFd < 0)
959 {
960 std::cerr << "Failed to get " << name << " fd\n";
961 return false;
962 }
963
964 gpioEventDescriptor.assign(gpioLineFd);
965
966 gpioEventDescriptor.async_wait(
967 boost::asio::posix::stream_descriptor::wait_read,
968 [&name, handler](const boost::system::error_code ec) {
969 if (ec)
970 {
971 std::cerr << name << " fd handler error: " << ec.message()
972 << "\n";
973 // TODO: throw here to force power-control to restart?
974 return;
975 }
976 handler();
977 });
978 return true;
979}
980
981static bool setGPIOOutput(const std::string& name, const int value,
982 gpiod::line& gpioLine)
983{
984 // Find the GPIO line
985 gpioLine = gpiod::find_line(name);
986 if (!gpioLine)
987 {
988 std::cerr << "Failed to find the " << name << " line.\n";
989 return false;
990 }
991
992 // Request GPIO output to specified value
993 try
994 {
995 gpioLine.request({__FUNCTION__, gpiod::line_request::DIRECTION_OUTPUT},
996 value);
997 }
998 catch (std::exception&)
999 {
1000 std::cerr << "Failed to request " << name << " output\n";
1001 return false;
1002 }
1003
1004 std::cerr << name << " set to " << std::to_string(value) << "\n";
1005 return true;
1006}
1007
1008static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1009 const std::string& name, const int value,
1010 const int durationMs)
1011{
1012 // Set the masked GPIO line to the specified value
1013 maskedGPIOLine.set_value(value);
1014 std::cerr << name << " set to " << std::to_string(value) << "\n";
1015 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
1016 gpioAssertTimer.async_wait(
1017 [maskedGPIOLine, value, name](const boost::system::error_code ec) {
1018 // Set the masked GPIO line back to the opposite value
1019 maskedGPIOLine.set_value(!value);
1020 std::cerr << name << " released\n";
1021 if (ec)
1022 {
1023 // operation_aborted is expected if timer is canceled before
1024 // completion.
1025 if (ec != boost::asio::error::operation_aborted)
1026 {
1027 std::cerr << name << " async_wait failed: " + ec.message()
1028 << "\n";
1029 }
1030 }
1031 });
1032 return 0;
1033}
1034
1035static int setGPIOOutputForMs(const std::string& name, const int value,
1036 const int durationMs)
1037{
1038 // If the requested GPIO is masked, use the mask line to set the output
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001039 if (powerButtonMask && name == power_control::powerOutName)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001040 {
1041 return setMaskedGPIOOutputForMs(powerButtonMask, name, value,
1042 durationMs);
1043 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001044 if (resetButtonMask && name == power_control::resetOutName)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001045 {
1046 return setMaskedGPIOOutputForMs(resetButtonMask, name, value,
1047 durationMs);
1048 }
1049
1050 // No mask set, so request and set the GPIO normally
1051 gpiod::line gpioLine;
1052 if (!setGPIOOutput(name, value, gpioLine))
1053 {
1054 return -1;
1055 }
1056 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
1057 gpioAssertTimer.async_wait(
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001058 [gpioLine, value, name](const boost::system::error_code ec) {
1059 // Set the GPIO line back to the opposite value
1060 gpioLine.set_value(!value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001061 std::cerr << name << " released\n";
1062 if (ec)
1063 {
1064 // operation_aborted is expected if timer is canceled before
1065 // completion.
1066 if (ec != boost::asio::error::operation_aborted)
1067 {
1068 std::cerr << name << " async_wait failed: " << ec.message()
1069 << "\n";
1070 }
1071 }
1072 });
1073 return 0;
1074}
1075
1076static void powerOn()
1077{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001078 setGPIOOutputForMs(power_control::powerOutName, 0, powerPulseTimeMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001079}
1080
1081static void gracefulPowerOff()
1082{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001083 setGPIOOutputForMs(power_control::powerOutName, 0, powerPulseTimeMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001084}
1085
1086static void forcePowerOff()
1087{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001088 if (setGPIOOutputForMs(power_control::powerOutName, 0,
1089 forceOffPulseTimeMs) < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001090 {
1091 return;
1092 }
1093
1094 // If the force off timer expires, then the PCH power-button override
1095 // failed, so attempt the Unconditional Powerdown SMBus command.
1096 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1097 if (ec)
1098 {
1099 // operation_aborted is expected if timer is canceled before
1100 // completion.
1101 if (ec != boost::asio::error::operation_aborted)
1102 {
1103 std::cerr << "Force power off async_wait failed: "
1104 << ec.message() << "\n";
1105 }
1106 return;
1107 }
1108 std::cerr << "PCH Power-button override failed. Issuing Unconditional "
1109 "Powerdown SMBus command.\n";
1110 const static constexpr size_t pchDevBusAddress = 3;
1111 const static constexpr size_t pchDevSlaveAddress = 0x44;
1112 const static constexpr size_t pchCmdReg = 0;
1113 const static constexpr size_t pchPowerDownCmd = 0x02;
1114 if (i2cSet(pchDevBusAddress, pchDevSlaveAddress, pchCmdReg,
1115 pchPowerDownCmd) < 0)
1116 {
1117 std::cerr << "Unconditional Powerdown command failed! Not sure "
1118 "what to do now.\n";
1119 }
1120 });
1121}
1122
1123static void reset()
1124{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001125 setGPIOOutputForMs(power_control::resetOutName, 0, resetPulseTimeMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001126}
1127
1128static void gracefulPowerOffTimerStart()
1129{
1130 std::cerr << "Graceful power-off timer started\n";
1131 gracefulPowerOffTimer.expires_after(
1132 std::chrono::milliseconds(gracefulPowerOffTimeMs));
1133 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1134 if (ec)
1135 {
1136 // operation_aborted is expected if timer is canceled before
1137 // completion.
1138 if (ec != boost::asio::error::operation_aborted)
1139 {
1140 std::cerr << "Graceful power-off async_wait failed: "
1141 << ec.message() << "\n";
1142 }
1143 std::cerr << "Graceful power-off timer canceled\n";
1144 return;
1145 }
1146 std::cerr << "Graceful power-off timer completed\n";
1147 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1148 });
1149}
1150
1151static void powerCycleTimerStart()
1152{
1153 std::cerr << "Power-cycle timer started\n";
1154 powerCycleTimer.expires_after(std::chrono::milliseconds(powerCycleTimeMs));
1155 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1156 if (ec)
1157 {
1158 // operation_aborted is expected if timer is canceled before
1159 // completion.
1160 if (ec != boost::asio::error::operation_aborted)
1161 {
1162 std::cerr << "Power-cycle async_wait failed: " << ec.message()
1163 << "\n";
1164 }
1165 std::cerr << "Power-cycle timer canceled\n";
1166 return;
1167 }
1168 std::cerr << "Power-cycle timer completed\n";
1169 sendPowerControlEvent(Event::powerCycleTimerExpired);
1170 });
1171}
1172
1173static void psPowerOKWatchdogTimerStart()
1174{
1175 std::cerr << "power supply power OK watchdog timer started\n";
1176 psPowerOKWatchdogTimer.expires_after(
1177 std::chrono::milliseconds(psPowerOKWatchdogTimeMs));
1178 psPowerOKWatchdogTimer.async_wait(
1179 [](const boost::system::error_code ec) {
1180 if (ec)
1181 {
1182 // operation_aborted is expected if timer is canceled before
1183 // completion.
1184 if (ec != boost::asio::error::operation_aborted)
1185 {
1186 std::cerr
1187 << "power supply power OK watchdog async_wait failed: "
1188 << ec.message() << "\n";
1189 }
1190 std::cerr << "power supply power OK watchdog timer canceled\n";
1191 return;
1192 }
1193 std::cerr << "power supply power OK watchdog timer expired\n";
1194 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1195 });
1196}
1197
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001198static void warmResetCheckTimerStart()
1199{
1200 std::cerr << "Warm reset check timer started\n";
1201 warmResetCheckTimer.expires_after(
1202 std::chrono::milliseconds(warmResetCheckTimeMs));
1203 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1204 if (ec)
1205 {
1206 // operation_aborted is expected if timer is canceled before
1207 // completion.
1208 if (ec != boost::asio::error::operation_aborted)
1209 {
1210 std::cerr << "Warm reset check async_wait failed: "
1211 << ec.message() << "\n";
1212 }
1213 std::cerr << "Warm reset check timer canceled\n";
1214 return;
1215 }
1216 std::cerr << "Warm reset check timer completed\n";
1217 sendPowerControlEvent(Event::warmResetDetected);
1218 });
1219}
1220
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001221static void pohCounterTimerStart()
1222{
1223 std::cerr << "POH timer started\n";
1224 // Set the time-out as 1 hour, to align with POH command in ipmid
1225 pohCounterTimer.expires_after(std::chrono::hours(1));
1226 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1227 if (ec)
1228 {
1229 // operation_aborted is expected if timer is canceled before
1230 // completion.
1231 if (ec != boost::asio::error::operation_aborted)
1232 {
1233 std::cerr << "POH timer async_wait failed: " << ec.message()
1234 << "\n";
1235 }
1236 std::cerr << "POH timer canceled\n";
1237 return;
1238 }
1239
1240 if (getHostState(powerState) !=
1241 "xyz.openbmc_project.State.Host.HostState.Running")
1242 {
1243 return;
1244 }
1245
1246 conn->async_method_call(
1247 [](boost::system::error_code ec,
1248 const std::variant<uint32_t>& pohCounterProperty) {
1249 if (ec)
1250 {
1251 std::cerr << "error to get poh counter\n";
1252 return;
1253 }
1254 const uint32_t* pohCounter =
1255 std::get_if<uint32_t>(&pohCounterProperty);
1256 if (pohCounter == nullptr)
1257 {
1258 std::cerr << "unable to read poh counter\n";
1259 return;
1260 }
1261
1262 conn->async_method_call(
1263 [](boost::system::error_code ec) {
1264 if (ec)
1265 {
1266 std::cerr << "failed to set poh counter\n";
1267 }
1268 },
1269 "xyz.openbmc_project.Settings",
1270 "/xyz/openbmc_project/state/chassis0",
1271 "org.freedesktop.DBus.Properties", "Set",
1272 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1273 std::variant<uint32_t>(*pohCounter + 1));
1274 },
1275 "xyz.openbmc_project.Settings",
1276 "/xyz/openbmc_project/state/chassis0",
1277 "org.freedesktop.DBus.Properties", "Get",
1278 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1279
1280 pohCounterTimerStart();
1281 });
1282}
1283
1284static void currentHostStateMonitor()
1285{
Yong Li8d660212019-12-27 10:18:10 +08001286 if (getHostState(powerState) ==
1287 "xyz.openbmc_project.State.Host.HostState.Running")
1288 {
1289 pohCounterTimerStart();
1290 // Clear the restart cause set for the next restart
1291 clearRestartCause();
1292 }
1293 else
1294 {
1295 pohCounterTimer.cancel();
1296 // Set the restart cause set for this restart
1297 setRestartCause();
1298 }
1299
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001300 static auto match = sdbusplus::bus::match::match(
1301 *conn,
1302 "type='signal',member='PropertiesChanged', "
1303 "interface='org.freedesktop.DBus.Properties', "
1304 "arg0namespace='xyz.openbmc_project.State.Host'",
1305 [](sdbusplus::message::message& message) {
1306 std::string intfName;
1307 std::map<std::string, std::variant<std::string>> properties;
1308
1309 message.read(intfName, properties);
1310
1311 std::variant<std::string> currentHostState;
1312
1313 try
1314 {
1315 currentHostState = properties.at("CurrentHostState");
1316 }
1317 catch (const std::out_of_range& e)
1318 {
1319 std::cerr << "Error in finding CurrentHostState property\n";
1320
1321 return;
1322 }
1323
1324 if (std::get<std::string>(currentHostState) ==
1325 "xyz.openbmc_project.State.Host.HostState.Running")
1326 {
1327 pohCounterTimerStart();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001328 // Clear the restart cause set for the next restart
1329 clearRestartCause();
Yong Li8d660212019-12-27 10:18:10 +08001330 sd_journal_send("MESSAGE=Host system DC power is on",
1331 "PRIORITY=%i", LOG_INFO,
1332 "REDFISH_MESSAGE_ID=%s",
1333 "OpenBMC.0.1.DCPowerOn", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001334 }
1335 else
1336 {
1337 pohCounterTimer.cancel();
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301338 // POST_COMPLETE GPIO event is not working in some platforms
1339 // when power state is changed to OFF. This resulted in
1340 // 'OperatingSystemState' to stay at 'Standby', even though
1341 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1342 // if HostState is trurned to OFF.
1343 osIface->set_property("OperatingSystemState",
1344 std::string("Inactive"));
1345
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001346 // Set the restart cause set for this restart
1347 setRestartCause();
Rashmi RV89f61312020-01-22 15:41:50 +05301348 resetACBootProperty();
Yong Li8d660212019-12-27 10:18:10 +08001349 sd_journal_send("MESSAGE=Host system DC power is off",
1350 "PRIORITY=%i", LOG_INFO,
1351 "REDFISH_MESSAGE_ID=%s",
1352 "OpenBMC.0.1.DCPowerOff", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001353 }
1354 });
1355}
1356
1357static void sioPowerGoodWatchdogTimerStart()
1358{
1359 std::cerr << "SIO power good watchdog timer started\n";
1360 sioPowerGoodWatchdogTimer.expires_after(
1361 std::chrono::milliseconds(sioPowerGoodWatchdogTimeMs));
1362 sioPowerGoodWatchdogTimer.async_wait(
1363 [](const boost::system::error_code ec) {
1364 if (ec)
1365 {
1366 // operation_aborted is expected if timer is canceled before
1367 // completion.
1368 if (ec != boost::asio::error::operation_aborted)
1369 {
1370 std::cerr << "SIO power good watchdog async_wait failed: "
1371 << ec.message() << "\n";
1372 }
1373 std::cerr << "SIO power good watchdog timer canceled\n";
1374 return;
1375 }
1376 std::cerr << "SIO power good watchdog timer completed\n";
1377 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1378 });
1379}
1380
1381static void powerStateOn(const Event event)
1382{
1383 logEvent(__FUNCTION__, event);
1384 switch (event)
1385 {
1386 case Event::psPowerOKDeAssert:
1387 setPowerState(PowerState::off);
1388 // DC power is unexpectedly lost, beep
1389 beep(beepPowerFail);
1390 break;
1391 case Event::sioS5Assert:
1392 setPowerState(PowerState::transitionToOff);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001393 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001394 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001395 case Event::postCompleteDeAssert:
1396 setPowerState(PowerState::checkForWarmReset);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001397 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001398 warmResetCheckTimerStart();
1399 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001400 case Event::powerButtonPressed:
1401 setPowerState(PowerState::gracefulTransitionToOff);
1402 gracefulPowerOffTimerStart();
1403 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001404 case Event::resetButtonPressed:
1405 setPowerState(PowerState::checkForWarmReset);
1406 warmResetCheckTimerStart();
1407 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001408 case Event::powerOffRequest:
1409 setPowerState(PowerState::transitionToOff);
1410 forcePowerOff();
1411 break;
1412 case Event::gracefulPowerOffRequest:
1413 setPowerState(PowerState::gracefulTransitionToOff);
1414 gracefulPowerOffTimerStart();
1415 gracefulPowerOff();
1416 break;
1417 case Event::powerCycleRequest:
1418 setPowerState(PowerState::transitionToCycleOff);
1419 forcePowerOff();
1420 break;
1421 case Event::gracefulPowerCycleRequest:
1422 setPowerState(PowerState::gracefulTransitionToCycleOff);
1423 gracefulPowerOffTimerStart();
1424 gracefulPowerOff();
1425 break;
1426 case Event::resetRequest:
1427 reset();
1428 break;
1429 default:
1430 std::cerr << "No action taken.\n";
1431 break;
1432 }
1433}
1434
1435static void powerStateWaitForPSPowerOK(const Event event)
1436{
1437 logEvent(__FUNCTION__, event);
1438 switch (event)
1439 {
1440 case Event::psPowerOKAssert:
1441 // Cancel any GPIO assertions held during the transition
1442 gpioAssertTimer.cancel();
1443 psPowerOKWatchdogTimer.cancel();
1444 sioPowerGoodWatchdogTimerStart();
1445 setPowerState(PowerState::waitForSIOPowerGood);
1446 break;
1447 case Event::psPowerOKWatchdogTimerExpired:
1448 setPowerState(PowerState::failedTransitionToOn);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001449 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001450 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001451 case Event::sioPowerGoodAssert:
1452 psPowerOKWatchdogTimer.cancel();
1453 setPowerState(PowerState::on);
1454 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001455 default:
1456 std::cerr << "No action taken.\n";
1457 break;
1458 }
1459}
1460
1461static void powerStateWaitForSIOPowerGood(const Event event)
1462{
1463 logEvent(__FUNCTION__, event);
1464 switch (event)
1465 {
1466 case Event::sioPowerGoodAssert:
1467 sioPowerGoodWatchdogTimer.cancel();
1468 setPowerState(PowerState::on);
1469 break;
1470 case Event::sioPowerGoodWatchdogTimerExpired:
1471 setPowerState(PowerState::failedTransitionToOn);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001472 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001473 forcePowerOff();
1474 break;
1475 default:
1476 std::cerr << "No action taken.\n";
1477 break;
1478 }
1479}
1480
1481static void powerStateFailedTransitionToOn(const Event event)
1482{
1483 logEvent(__FUNCTION__, event);
1484 switch (event)
1485 {
1486 case Event::psPowerOKAssert:
1487 // We're in a failure state, so don't allow the system to turn on
1488 // without a user request
1489 forcePowerOff();
1490 break;
1491 case Event::psPowerOKDeAssert:
1492 // Cancel any GPIO assertions held during the transition
1493 gpioAssertTimer.cancel();
1494 break;
1495 case Event::powerButtonPressed:
1496 psPowerOKWatchdogTimerStart();
1497 setPowerState(PowerState::waitForPSPowerOK);
1498 break;
1499 case Event::powerOnRequest:
1500 psPowerOKWatchdogTimerStart();
1501 setPowerState(PowerState::waitForPSPowerOK);
1502 powerOn();
1503 break;
1504 default:
1505 std::cerr << "No action taken.\n";
1506 break;
1507 }
1508}
1509
1510static void powerStateOff(const Event event)
1511{
1512 logEvent(__FUNCTION__, event);
1513 switch (event)
1514 {
1515 case Event::psPowerOKAssert:
1516 setPowerState(PowerState::waitForSIOPowerGood);
1517 break;
1518 case Event::sioS5DeAssert:
1519 setPowerState(PowerState::waitForPSPowerOK);
1520 break;
1521 case Event::powerButtonPressed:
1522 psPowerOKWatchdogTimerStart();
1523 setPowerState(PowerState::waitForPSPowerOK);
1524 break;
1525 case Event::powerOnRequest:
1526 psPowerOKWatchdogTimerStart();
1527 setPowerState(PowerState::waitForPSPowerOK);
1528 powerOn();
1529 break;
1530 default:
1531 std::cerr << "No action taken.\n";
1532 break;
1533 }
1534}
1535
1536static void powerStateTransitionToOff(const Event event)
1537{
1538 logEvent(__FUNCTION__, event);
1539 switch (event)
1540 {
1541 case Event::psPowerOKDeAssert:
1542 // Cancel any GPIO assertions held during the transition
1543 gpioAssertTimer.cancel();
1544 setPowerState(PowerState::off);
1545 break;
1546 default:
1547 std::cerr << "No action taken.\n";
1548 break;
1549 }
1550}
1551
1552static void powerStateGracefulTransitionToOff(const Event event)
1553{
1554 logEvent(__FUNCTION__, event);
1555 switch (event)
1556 {
1557 case Event::psPowerOKDeAssert:
1558 gracefulPowerOffTimer.cancel();
1559 setPowerState(PowerState::off);
1560 break;
1561 case Event::gracefulPowerOffTimerExpired:
1562 setPowerState(PowerState::on);
1563 break;
1564 default:
1565 std::cerr << "No action taken.\n";
1566 break;
1567 }
1568}
1569
1570static void powerStateCycleOff(const Event event)
1571{
1572 logEvent(__FUNCTION__, event);
1573 switch (event)
1574 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001575 case Event::psPowerOKAssert:
1576 powerCycleTimer.cancel();
1577 setPowerState(PowerState::waitForSIOPowerGood);
1578 break;
1579 case Event::sioS5DeAssert:
1580 powerCycleTimer.cancel();
1581 setPowerState(PowerState::waitForPSPowerOK);
1582 break;
1583 case Event::powerButtonPressed:
1584 powerCycleTimer.cancel();
1585 psPowerOKWatchdogTimerStart();
1586 setPowerState(PowerState::waitForPSPowerOK);
1587 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001588 case Event::powerCycleTimerExpired:
1589 psPowerOKWatchdogTimerStart();
1590 setPowerState(PowerState::waitForPSPowerOK);
1591 powerOn();
1592 break;
1593 default:
1594 std::cerr << "No action taken.\n";
1595 break;
1596 }
1597}
1598
1599static void powerStateTransitionToCycleOff(const Event event)
1600{
1601 logEvent(__FUNCTION__, event);
1602 switch (event)
1603 {
1604 case Event::psPowerOKDeAssert:
1605 // Cancel any GPIO assertions held during the transition
1606 gpioAssertTimer.cancel();
1607 setPowerState(PowerState::cycleOff);
1608 powerCycleTimerStart();
1609 break;
1610 default:
1611 std::cerr << "No action taken.\n";
1612 break;
1613 }
1614}
1615
1616static void powerStateGracefulTransitionToCycleOff(const Event event)
1617{
1618 logEvent(__FUNCTION__, event);
1619 switch (event)
1620 {
1621 case Event::psPowerOKDeAssert:
1622 gracefulPowerOffTimer.cancel();
1623 setPowerState(PowerState::cycleOff);
1624 powerCycleTimerStart();
1625 break;
1626 case Event::gracefulPowerOffTimerExpired:
1627 setPowerState(PowerState::on);
1628 break;
1629 default:
1630 std::cerr << "No action taken.\n";
1631 break;
1632 }
1633}
1634
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001635static void powerStateCheckForWarmReset(const Event event)
1636{
1637 logEvent(__FUNCTION__, event);
1638 switch (event)
1639 {
1640 case Event::sioS5Assert:
1641 warmResetCheckTimer.cancel();
1642 setPowerState(PowerState::transitionToOff);
1643 break;
1644 case Event::warmResetDetected:
1645 setPowerState(PowerState::on);
1646 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001647 case Event::psPowerOKDeAssert:
1648 warmResetCheckTimer.cancel();
1649 setPowerState(PowerState::off);
1650 // DC power is unexpectedly lost, beep
1651 beep(beepPowerFail);
1652 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001653 default:
1654 std::cerr << "No action taken.\n";
1655 break;
1656 }
1657}
1658
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001659static void psPowerOKHandler()
1660{
1661 gpiod::line_event gpioLineEvent = psPowerOKLine.event_read();
1662
1663 Event powerControlEvent =
1664 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
1665 ? Event::psPowerOKAssert
1666 : Event::psPowerOKDeAssert;
1667
1668 sendPowerControlEvent(powerControlEvent);
1669 psPowerOKEvent.async_wait(
1670 boost::asio::posix::stream_descriptor::wait_read,
1671 [](const boost::system::error_code ec) {
1672 if (ec)
1673 {
1674 std::cerr << "power supply power OK handler error: "
1675 << ec.message() << "\n";
1676 return;
1677 }
1678 psPowerOKHandler();
1679 });
1680}
1681
1682static void sioPowerGoodHandler()
1683{
1684 gpiod::line_event gpioLineEvent = sioPowerGoodLine.event_read();
1685
1686 Event powerControlEvent =
1687 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
1688 ? Event::sioPowerGoodAssert
1689 : Event::sioPowerGoodDeAssert;
1690
1691 sendPowerControlEvent(powerControlEvent);
1692 sioPowerGoodEvent.async_wait(
1693 boost::asio::posix::stream_descriptor::wait_read,
1694 [](const boost::system::error_code ec) {
1695 if (ec)
1696 {
1697 std::cerr << "SIO power good handler error: " << ec.message()
1698 << "\n";
1699 return;
1700 }
1701 sioPowerGoodHandler();
1702 });
1703}
1704
1705static void sioOnControlHandler()
1706{
1707 gpiod::line_event gpioLineEvent = sioOnControlLine.event_read();
1708
1709 bool sioOnControl =
1710 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE;
1711 std::cerr << "SIO_ONCONTROL value changed: " << sioOnControl << "\n";
1712 sioOnControlEvent.async_wait(
1713 boost::asio::posix::stream_descriptor::wait_read,
1714 [](const boost::system::error_code ec) {
1715 if (ec)
1716 {
1717 std::cerr << "SIO ONCONTROL handler error: " << ec.message()
1718 << "\n";
1719 return;
1720 }
1721 sioOnControlHandler();
1722 });
1723}
1724
1725static void sioS5Handler()
1726{
1727 gpiod::line_event gpioLineEvent = sioS5Line.event_read();
1728
1729 Event powerControlEvent =
1730 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE
1731 ? Event::sioS5Assert
1732 : Event::sioS5DeAssert;
1733
1734 sendPowerControlEvent(powerControlEvent);
1735 sioS5Event.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1736 [](const boost::system::error_code ec) {
1737 if (ec)
1738 {
1739 std::cerr << "SIO S5 handler error: "
1740 << ec.message() << "\n";
1741 return;
1742 }
1743 sioS5Handler();
1744 });
1745}
1746
1747static void powerButtonHandler()
1748{
1749 gpiod::line_event gpioLineEvent = powerButtonLine.event_read();
1750
1751 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1752 {
1753 powerButtonPressLog();
1754 powerButtonIface->set_property("ButtonPressed", true);
1755 if (!powerButtonMask)
1756 {
1757 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001758 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001759 }
1760 else
1761 {
1762 std::cerr << "power button press masked\n";
1763 }
1764 }
1765 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
1766 {
1767 powerButtonIface->set_property("ButtonPressed", false);
1768 }
1769 powerButtonEvent.async_wait(
1770 boost::asio::posix::stream_descriptor::wait_read,
1771 [](const boost::system::error_code ec) {
1772 if (ec)
1773 {
1774 std::cerr << "power button handler error: " << ec.message()
1775 << "\n";
1776 return;
1777 }
1778 powerButtonHandler();
1779 });
1780}
1781
1782static void resetButtonHandler()
1783{
1784 gpiod::line_event gpioLineEvent = resetButtonLine.event_read();
1785
1786 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1787 {
1788 resetButtonPressLog();
1789 resetButtonIface->set_property("ButtonPressed", true);
1790 if (!resetButtonMask)
1791 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001792 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001793 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001794 }
1795 else
1796 {
1797 std::cerr << "reset button press masked\n";
1798 }
1799 }
1800 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
1801 {
1802 resetButtonIface->set_property("ButtonPressed", false);
1803 }
1804 resetButtonEvent.async_wait(
1805 boost::asio::posix::stream_descriptor::wait_read,
1806 [](const boost::system::error_code ec) {
1807 if (ec)
1808 {
1809 std::cerr << "reset button handler error: " << ec.message()
1810 << "\n";
1811 return;
1812 }
1813 resetButtonHandler();
1814 });
1815}
1816
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07001817static constexpr auto systemdBusname = "org.freedesktop.systemd1";
1818static constexpr auto systemdPath = "/org/freedesktop/systemd1";
1819static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
1820static constexpr auto systemTargetName = "chassis-system-reset.target";
1821
1822void systemReset()
1823{
1824 conn->async_method_call(
1825 [](boost::system::error_code ec) {
1826 if (ec)
1827 {
1828 phosphor::logging::log<phosphor::logging::level::ERR>(
1829 "Failed to call chassis system reset",
1830 phosphor::logging::entry("ERR=%s", ec.message().c_str()));
1831 }
1832 },
1833 systemdBusname, systemdPath, systemdInterface, "StartUnit",
1834 systemTargetName, "replace");
1835}
1836
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001837static void nmiSetEnablePorperty(bool value)
1838{
1839 conn->async_method_call(
1840 [](boost::system::error_code ec) {
1841 if (ec)
1842 {
1843 std::cerr << "failed to set NMI source\n";
1844 }
1845 },
Chen Yugang303bd582019-11-01 08:45:06 +08001846 "xyz.openbmc_project.Settings",
1847 "/xyz/openbmc_project/Chassis/Control/NMISource",
1848 "org.freedesktop.DBus.Properties", "Set",
1849 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
1850 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001851}
1852
1853static void nmiReset(void)
1854{
1855 static constexpr const uint8_t value = 1;
1856 const static constexpr int nmiOutPulseTimeMs = 200;
1857
1858 std::cerr << "NMI out action \n";
1859 nmiOutLine.set_value(value);
1860 std::cerr << nmiOutName << " set to " << std::to_string(value) << "\n";
1861 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
1862 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1863 // restore the NMI_OUT GPIO line back to the opposite value
1864 nmiOutLine.set_value(!value);
1865 std::cerr << nmiOutName << " released\n";
1866 if (ec)
1867 {
1868 // operation_aborted is expected if timer is canceled before
1869 // completion.
1870 if (ec != boost::asio::error::operation_aborted)
1871 {
1872 std::cerr << nmiOutName << " async_wait failed: " + ec.message()
1873 << "\n";
1874 }
1875 }
1876 });
1877 // log to redfish
1878 nmiDiagIntLog();
1879 std::cerr << "NMI out action completed\n";
1880 // reset Enable Property
1881 nmiSetEnablePorperty(false);
1882}
1883
1884static void nmiSourcePropertyMonitor(void)
1885{
1886 std::cerr << " NMI Source Property Monitor \n";
1887
1888 static std::unique_ptr<sdbusplus::bus::match::match> nmiSourceMatch =
1889 std::make_unique<sdbusplus::bus::match::match>(
1890 *conn,
1891 "type='signal',interface='org.freedesktop.DBus.Properties',"
Chen Yugang303bd582019-11-01 08:45:06 +08001892 "member='PropertiesChanged',arg0namespace='xyz.openbmc_project."
1893 "Chassis.Control."
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001894 "NMISource'",
1895 [](sdbusplus::message::message& msg) {
1896 std::string interfaceName;
1897 boost::container::flat_map<std::string,
1898 std::variant<bool, std::string>>
1899 propertiesChanged;
1900 std::string state;
1901 bool value = true;
1902 try
1903 {
1904 msg.read(interfaceName, propertiesChanged);
1905 if (propertiesChanged.begin()->first == "Enabled")
1906 {
1907 value =
1908 std::get<bool>(propertiesChanged.begin()->second);
1909 std::cerr
1910 << " NMI Enabled propertiesChanged value: " << value
1911 << "\n";
1912 nmiEnabled = value;
1913 if (nmiEnabled)
1914 {
1915 nmiReset();
1916 }
1917 }
1918 }
1919 catch (std::exception& e)
1920 {
1921 std::cerr << "Unable to read NMI source\n";
1922 return;
1923 }
1924 });
1925}
1926
1927static void setNmiSource()
1928{
1929 conn->async_method_call(
1930 [](boost::system::error_code ec) {
1931 if (ec)
1932 {
1933 std::cerr << "failed to set NMI source\n";
1934 }
1935 },
Chen Yugang303bd582019-11-01 08:45:06 +08001936 "xyz.openbmc_project.Settings",
1937 "/xyz/openbmc_project/Chassis/Control/NMISource",
1938 "org.freedesktop.DBus.Properties", "Set",
1939 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
1940 std::variant<std::string>{"xyz.openbmc_project.Chassis.Control."
1941 "NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001942 // set Enable Property
1943 nmiSetEnablePorperty(true);
1944}
1945
1946static void nmiButtonHandler()
1947{
1948 gpiod::line_event gpioLineEvent = nmiButtonLine.event_read();
1949
1950 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1951 {
1952 nmiButtonPressLog();
1953 nmiButtonIface->set_property("ButtonPressed", true);
1954 if (nmiButtonMasked)
1955 {
1956 std::cerr << "NMI button press masked\n";
1957 }
1958 else
1959 {
1960 setNmiSource();
1961 }
1962 }
1963 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
1964 {
1965 nmiButtonIface->set_property("ButtonPressed", false);
1966 }
1967 nmiButtonEvent.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1968 [](const boost::system::error_code ec) {
1969 if (ec)
1970 {
1971 std::cerr << "NMI button handler error: "
1972 << ec.message() << "\n";
1973 return;
1974 }
1975 nmiButtonHandler();
1976 });
1977}
1978
1979static void idButtonHandler()
1980{
1981 gpiod::line_event gpioLineEvent = idButtonLine.event_read();
1982
1983 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1984 {
1985 idButtonIface->set_property("ButtonPressed", true);
1986 }
1987 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
1988 {
1989 idButtonIface->set_property("ButtonPressed", false);
1990 }
1991 idButtonEvent.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1992 [](const boost::system::error_code& ec) {
1993 if (ec)
1994 {
1995 std::cerr << "ID button handler error: "
1996 << ec.message() << "\n";
1997 return;
1998 }
1999 idButtonHandler();
2000 });
2001}
2002
2003static void postCompleteHandler()
2004{
2005 gpiod::line_event gpioLineEvent = postCompleteLine.event_read();
2006
2007 bool postComplete =
2008 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002009 if (postComplete)
2010 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002011 sendPowerControlEvent(Event::postCompleteAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002012 osIface->set_property("OperatingSystemState", std::string("Standby"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002013 }
2014 else
2015 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002016 sendPowerControlEvent(Event::postCompleteDeAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002017 osIface->set_property("OperatingSystemState", std::string("Inactive"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002018 }
2019 postCompleteEvent.async_wait(
2020 boost::asio::posix::stream_descriptor::wait_read,
2021 [](const boost::system::error_code ec) {
2022 if (ec)
2023 {
2024 std::cerr << "POST complete handler error: " << ec.message()
2025 << "\n";
2026 return;
2027 }
2028 postCompleteHandler();
2029 });
2030}
2031} // namespace power_control
2032
2033int main(int argc, char* argv[])
2034{
2035 std::cerr << "Start Chassis power control service...\n";
2036 power_control::conn =
2037 std::make_shared<sdbusplus::asio::connection>(power_control::io);
2038
2039 // Request all the dbus names
2040 power_control::conn->request_name("xyz.openbmc_project.State.Host");
2041 power_control::conn->request_name("xyz.openbmc_project.State.Chassis");
2042 power_control::conn->request_name(
2043 "xyz.openbmc_project.State.OperatingSystem");
2044 power_control::conn->request_name("xyz.openbmc_project.Chassis.Buttons");
Chen Yugang174ec662019-08-19 19:58:49 +08002045 power_control::conn->request_name("xyz.openbmc_project.Control.Host.NMI");
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002046 power_control::conn->request_name(
2047 "xyz.openbmc_project.Control.Host.RestartCause");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002048
2049 // Request PS_PWROK GPIO events
2050 if (!power_control::requestGPIOEvents(
2051 "PS_PWROK", power_control::psPowerOKHandler,
2052 power_control::psPowerOKLine, power_control::psPowerOKEvent))
2053 {
2054 return -1;
2055 }
2056
2057 // Request SIO_POWER_GOOD GPIO events
2058 if (!power_control::requestGPIOEvents(
2059 "SIO_POWER_GOOD", power_control::sioPowerGoodHandler,
2060 power_control::sioPowerGoodLine, power_control::sioPowerGoodEvent))
2061 {
2062 return -1;
2063 }
2064
2065 // Request SIO_ONCONTROL GPIO events
2066 if (!power_control::requestGPIOEvents(
2067 "SIO_ONCONTROL", power_control::sioOnControlHandler,
2068 power_control::sioOnControlLine, power_control::sioOnControlEvent))
2069 {
2070 return -1;
2071 }
2072
2073 // Request SIO_S5 GPIO events
2074 if (!power_control::requestGPIOEvents("SIO_S5", power_control::sioS5Handler,
2075 power_control::sioS5Line,
2076 power_control::sioS5Event))
2077 {
2078 return -1;
2079 }
2080
2081 // Request POWER_BUTTON GPIO events
2082 if (!power_control::requestGPIOEvents(
2083 "POWER_BUTTON", power_control::powerButtonHandler,
2084 power_control::powerButtonLine, power_control::powerButtonEvent))
2085 {
2086 return -1;
2087 }
2088
2089 // Request RESET_BUTTON GPIO events
2090 if (!power_control::requestGPIOEvents(
2091 "RESET_BUTTON", power_control::resetButtonHandler,
2092 power_control::resetButtonLine, power_control::resetButtonEvent))
2093 {
2094 return -1;
2095 }
2096
2097 // Request NMI_BUTTON GPIO events
Vijay Khemka33a532d2019-11-14 16:50:35 -08002098 power_control::requestGPIOEvents(
2099 "NMI_BUTTON", power_control::nmiButtonHandler,
2100 power_control::nmiButtonLine, power_control::nmiButtonEvent);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002101
2102 // Request ID_BUTTON GPIO events
Vijay Khemka33a532d2019-11-14 16:50:35 -08002103 power_control::requestGPIOEvents(
2104 "ID_BUTTON", power_control::idButtonHandler,
2105 power_control::idButtonLine, power_control::idButtonEvent);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002106
2107 // Request POST_COMPLETE GPIO events
2108 if (!power_control::requestGPIOEvents(
2109 "POST_COMPLETE", power_control::postCompleteHandler,
2110 power_control::postCompleteLine, power_control::postCompleteEvent))
2111 {
2112 return -1;
2113 }
2114
2115 // initialize NMI_OUT GPIO.
Vijay Khemka33a532d2019-11-14 16:50:35 -08002116 power_control::setGPIOOutput(power_control::nmiOutName, 0,
2117 power_control::nmiOutLine);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002118
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002119 // Initialize POWER_OUT and RESET_OUT GPIO.
2120 gpiod::line line;
2121 if (!power_control::setGPIOOutput(power_control::powerOutName, 1, line))
2122 {
2123 return -1;
2124 }
2125
2126 if (!power_control::setGPIOOutput(power_control::resetOutName, 1, line))
2127 {
2128 return -1;
2129 }
2130
2131 // Release line
2132 line.reset();
2133
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002134 // Initialize the power state
2135 power_control::powerState = power_control::PowerState::off;
2136 // Check power good
2137 if (power_control::psPowerOKLine.get_value() > 0)
2138 {
2139 power_control::powerState = power_control::PowerState::on;
2140 }
2141
2142 // Initialize the power state storage
2143 if (power_control::initializePowerStateStorage() < 0)
2144 {
2145 return -1;
2146 }
2147
2148 // Check if we need to start the Power Restore policy
2149 power_control::powerRestorePolicyCheck();
2150
Vijay Khemka33a532d2019-11-14 16:50:35 -08002151 if (power_control::nmiOutLine)
2152 power_control::nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002153
2154 std::cerr << "Initializing power state. ";
2155 power_control::logStateTransition(power_control::powerState);
2156
2157 // Power Control Service
2158 sdbusplus::asio::object_server hostServer =
2159 sdbusplus::asio::object_server(power_control::conn);
2160
2161 // Power Control Interface
2162 power_control::hostIface = hostServer.add_interface(
2163 "/xyz/openbmc_project/state/host0", "xyz.openbmc_project.State.Host");
2164
2165 power_control::hostIface->register_property(
2166 "RequestedHostTransition",
2167 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2168 [](const std::string& requested, std::string& resp) {
2169 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2170 {
2171 sendPowerControlEvent(
2172 power_control::Event::gracefulPowerOffRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002173 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002174 }
2175 else if (requested ==
2176 "xyz.openbmc_project.State.Host.Transition.On")
2177 {
2178 sendPowerControlEvent(power_control::Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002179 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002180 }
2181 else if (requested ==
2182 "xyz.openbmc_project.State.Host.Transition.Reboot")
2183 {
Jason M. Billse7520ba2020-01-31 11:19:03 -08002184 sendPowerControlEvent(power_control::Event::powerCycleRequest);
2185 addRestartCause(power_control::RestartCause::command);
2186 }
2187 else if (requested == "xyz.openbmc_project.State.Host.Transition."
2188 "GracefulWarmReboot")
2189 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002190 sendPowerControlEvent(
2191 power_control::Event::gracefulPowerCycleRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002192 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002193 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002194 else if (requested == "xyz.openbmc_project.State.Host.Transition."
2195 "ForceWarmReboot")
2196 {
2197 sendPowerControlEvent(power_control::Event::resetRequest);
2198 addRestartCause(power_control::RestartCause::command);
2199 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002200 else
2201 {
2202 std::cerr << "Unrecognized host state transition request.\n";
2203 throw std::invalid_argument("Unrecognized Transition Request");
2204 return 0;
2205 }
2206 resp = requested;
2207 return 1;
2208 });
2209 power_control::hostIface->register_property(
2210 "CurrentHostState",
2211 std::string(power_control::getHostState(power_control::powerState)));
2212
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002213 power_control::hostIface->initialize();
2214
2215 // Chassis Control Service
2216 sdbusplus::asio::object_server chassisServer =
2217 sdbusplus::asio::object_server(power_control::conn);
2218
2219 // Chassis Control Interface
2220 power_control::chassisIface =
2221 chassisServer.add_interface("/xyz/openbmc_project/state/chassis0",
2222 "xyz.openbmc_project.State.Chassis");
2223
2224 power_control::chassisIface->register_property(
2225 "RequestedPowerTransition",
2226 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
2227 [](const std::string& requested, std::string& resp) {
2228 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
2229 {
2230 sendPowerControlEvent(power_control::Event::powerOffRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002231 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002232 }
2233 else if (requested ==
2234 "xyz.openbmc_project.State.Chassis.Transition.On")
2235 {
2236 sendPowerControlEvent(power_control::Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002237 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002238 }
2239 else if (requested ==
2240 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2241 {
2242 sendPowerControlEvent(power_control::Event::powerCycleRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002243 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002244 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002245 else
2246 {
2247 std::cerr << "Unrecognized chassis state transition request.\n";
2248 throw std::invalid_argument("Unrecognized Transition Request");
2249 return 0;
2250 }
2251 resp = requested;
2252 return 1;
2253 });
2254 power_control::chassisIface->register_property(
2255 "CurrentPowerState",
2256 std::string(power_control::getChassisState(power_control::powerState)));
2257 power_control::chassisIface->register_property(
2258 "LastStateChangeTime", power_control::getCurrentTimeMs());
2259
2260 power_control::chassisIface->initialize();
2261
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002262 // Chassis System Service
2263 sdbusplus::asio::object_server chassisSysServer =
2264 sdbusplus::asio::object_server(power_control::conn);
2265
2266 // Chassis System Interface
2267 power_control::chassisSysIface = chassisSysServer.add_interface(
2268 "/xyz/openbmc_project/state/chassis_system0",
2269 "xyz.openbmc_project.State.Chassis");
2270
2271 power_control::chassisSysIface->register_property(
2272 "RequestedPowerTransition",
2273 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
2274 [](const std::string& requested, std::string& resp) {
2275 if (requested ==
2276 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2277 {
2278 power_control::systemReset();
2279 addRestartCause(power_control::RestartCause::command);
2280 }
2281 else
2282 {
2283 std::cerr << "Unrecognized chassis system state transition "
2284 "request.\n";
2285 throw std::invalid_argument("Unrecognized Transition Request");
2286 return 0;
2287 }
2288 resp = requested;
2289 return 1;
2290 });
2291 power_control::chassisSysIface->register_property(
2292 "CurrentPowerState",
2293 std::string(power_control::getChassisState(power_control::powerState)));
2294 power_control::chassisSysIface->register_property(
2295 "LastStateChangeTime", power_control::getCurrentTimeMs());
2296
2297 power_control::chassisSysIface->initialize();
2298
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002299 // Buttons Service
2300 sdbusplus::asio::object_server buttonsServer =
2301 sdbusplus::asio::object_server(power_control::conn);
2302
2303 // Power Button Interface
2304 power_control::powerButtonIface = buttonsServer.add_interface(
2305 "/xyz/openbmc_project/chassis/buttons/power",
2306 "xyz.openbmc_project.Chassis.Buttons");
2307
2308 power_control::powerButtonIface->register_property(
2309 "ButtonMasked", false, [](const bool requested, bool& current) {
2310 if (requested)
2311 {
2312 if (power_control::powerButtonMask)
2313 {
2314 return 1;
2315 }
2316 if (!power_control::setGPIOOutput(
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002317 power_control::powerOutName, 1,
2318 power_control::powerButtonMask))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002319 {
2320 throw std::runtime_error("Failed to request GPIO");
2321 return 0;
2322 }
2323 std::cerr << "Power Button Masked.\n";
2324 }
2325 else
2326 {
2327 if (!power_control::powerButtonMask)
2328 {
2329 return 1;
2330 }
2331 std::cerr << "Power Button Un-masked\n";
2332 power_control::powerButtonMask.reset();
2333 }
2334 // Update the mask setting
2335 current = requested;
2336 return 1;
2337 });
2338
2339 // Check power button state
2340 bool powerButtonPressed = power_control::powerButtonLine.get_value() == 0;
2341 power_control::powerButtonIface->register_property("ButtonPressed",
2342 powerButtonPressed);
2343
2344 power_control::powerButtonIface->initialize();
2345
2346 // Reset Button Interface
2347 power_control::resetButtonIface = buttonsServer.add_interface(
2348 "/xyz/openbmc_project/chassis/buttons/reset",
2349 "xyz.openbmc_project.Chassis.Buttons");
2350
2351 power_control::resetButtonIface->register_property(
2352 "ButtonMasked", false, [](const bool requested, bool& current) {
2353 if (requested)
2354 {
2355 if (power_control::resetButtonMask)
2356 {
2357 return 1;
2358 }
2359 if (!power_control::setGPIOOutput(
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002360 power_control::resetOutName, 1,
2361 power_control::resetButtonMask))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002362 {
2363 throw std::runtime_error("Failed to request GPIO");
2364 return 0;
2365 }
2366 std::cerr << "Reset Button Masked.\n";
2367 }
2368 else
2369 {
2370 if (!power_control::resetButtonMask)
2371 {
2372 return 1;
2373 }
2374 std::cerr << "Reset Button Un-masked\n";
2375 power_control::resetButtonMask.reset();
2376 }
2377 // Update the mask setting
2378 current = requested;
2379 return 1;
2380 });
2381
2382 // Check reset button state
2383 bool resetButtonPressed = power_control::resetButtonLine.get_value() == 0;
2384 power_control::resetButtonIface->register_property("ButtonPressed",
2385 resetButtonPressed);
2386
2387 power_control::resetButtonIface->initialize();
2388
Vijay Khemka33a532d2019-11-14 16:50:35 -08002389 if (power_control::nmiButtonLine)
2390 {
2391 // NMI Button Interface
2392 power_control::nmiButtonIface = buttonsServer.add_interface(
2393 "/xyz/openbmc_project/chassis/buttons/nmi",
2394 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002395
Vijay Khemka33a532d2019-11-14 16:50:35 -08002396 power_control::nmiButtonIface->register_property(
2397 "ButtonMasked", false, [](const bool requested, bool& current) {
2398 if (power_control::nmiButtonMasked == requested)
2399 {
2400 // NMI button mask is already set as requested, so no change
2401 return 1;
2402 }
2403 if (requested)
2404 {
2405 std::cerr << "NMI Button Masked.\n";
2406 power_control::nmiButtonMasked = true;
2407 }
2408 else
2409 {
2410 std::cerr << "NMI Button Un-masked.\n";
2411 power_control::nmiButtonMasked = false;
2412 }
2413 // Update the mask setting
2414 current = power_control::nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002415 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08002416 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002417
Vijay Khemka33a532d2019-11-14 16:50:35 -08002418 // Check NMI button state
2419 bool nmiButtonPressed = power_control::nmiButtonLine.get_value() == 0;
2420 power_control::nmiButtonIface->register_property("ButtonPressed",
2421 nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002422
Vijay Khemka33a532d2019-11-14 16:50:35 -08002423 power_control::nmiButtonIface->initialize();
2424 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002425
Vijay Khemka33a532d2019-11-14 16:50:35 -08002426 if (power_control::nmiOutLine)
2427 {
2428 // NMI out Service
2429 sdbusplus::asio::object_server nmiOutServer =
2430 sdbusplus::asio::object_server(power_control::conn);
Chen Yugang174ec662019-08-19 19:58:49 +08002431
Vijay Khemka33a532d2019-11-14 16:50:35 -08002432 // NMI out Interface
2433 power_control::nmiOutIface =
2434 nmiOutServer.add_interface("/xyz/openbmc_project/control/host0/nmi",
2435 "xyz.openbmc_project.Control.Host.NMI");
2436 power_control::nmiOutIface->register_method("NMI",
2437 power_control::nmiReset);
2438 power_control::nmiOutIface->initialize();
2439 }
Chen Yugang174ec662019-08-19 19:58:49 +08002440
Vijay Khemka33a532d2019-11-14 16:50:35 -08002441 if (power_control::idButtonLine)
2442 {
2443 // ID Button Interface
2444 power_control::idButtonIface = buttonsServer.add_interface(
2445 "/xyz/openbmc_project/chassis/buttons/id",
2446 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002447
Vijay Khemka33a532d2019-11-14 16:50:35 -08002448 // Check ID button state
2449 bool idButtonPressed = power_control::idButtonLine.get_value() == 0;
2450 power_control::idButtonIface->register_property("ButtonPressed",
2451 idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002452
Vijay Khemka33a532d2019-11-14 16:50:35 -08002453 power_control::idButtonIface->initialize();
2454 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002455
2456 // OS State Service
2457 sdbusplus::asio::object_server osServer =
2458 sdbusplus::asio::object_server(power_control::conn);
2459
2460 // OS State Interface
2461 power_control::osIface = osServer.add_interface(
2462 "/xyz/openbmc_project/state/os",
2463 "xyz.openbmc_project.State.OperatingSystem.Status");
2464
2465 // Get the initial OS state based on POST complete
2466 // 0: Asserted, OS state is "Standby" (ready to boot)
2467 // 1: De-Asserted, OS state is "Inactive"
2468 std::string osState = power_control::postCompleteLine.get_value() > 0
2469 ? "Inactive"
2470 : "Standby";
2471
2472 power_control::osIface->register_property("OperatingSystemState",
2473 std::string(osState));
2474
2475 power_control::osIface->initialize();
2476
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002477 // Restart Cause Service
2478 sdbusplus::asio::object_server restartCauseServer =
2479 sdbusplus::asio::object_server(power_control::conn);
2480
2481 // Restart Cause Interface
2482 power_control::restartCauseIface = restartCauseServer.add_interface(
2483 "/xyz/openbmc_project/control/host0/restart_cause",
2484 "xyz.openbmc_project.Control.Host.RestartCause");
2485
2486 power_control::restartCauseIface->register_property(
2487 "RestartCause",
2488 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
2489
2490 power_control::restartCauseIface->register_property(
2491 "RequestedRestartCause",
2492 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
2493 [](const std::string& requested, std::string& resp) {
2494 if (requested ==
2495 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
2496 {
2497 power_control::addRestartCause(
2498 power_control::RestartCause::watchdog);
2499 }
2500 else
2501 {
2502 throw std::invalid_argument(
2503 "Unrecognized RestartCause Request");
2504 return 0;
2505 }
2506
2507 std::cerr << "RestartCause requested: " << requested << "\n";
2508 resp = requested;
2509 return 1;
2510 });
2511
2512 power_control::restartCauseIface->initialize();
2513
Yong Li8d660212019-12-27 10:18:10 +08002514 power_control::currentHostStateMonitor();
2515
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002516 power_control::io.run();
2517
2518 return 0;
2519}