blob: b891c8c5e2630b2de4b3d0adac32decf7b82de43 [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 Khemkad6c5ad12020-05-27 14:57:52 -0700191 std::string logMsg =
192 "Host0: Moving to \"" + getPowerStateName(state) + "\" state";
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700193 phosphor::logging::log<phosphor::logging::level::INFO>(
194 logMsg.c_str(),
Vijay Khemkad6c5ad12020-05-27 14:57:52 -0700195 phosphor::logging::entry("STATE=%s", getPowerStateName(state).c_str()),
196 phosphor::logging::entry("HOST=0"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700197}
198
199enum class Event
200{
201 psPowerOKAssert,
202 psPowerOKDeAssert,
203 sioPowerGoodAssert,
204 sioPowerGoodDeAssert,
205 sioS5Assert,
206 sioS5DeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700207 postCompleteAssert,
208 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700209 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700210 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700211 powerCycleTimerExpired,
212 psPowerOKWatchdogTimerExpired,
213 sioPowerGoodWatchdogTimerExpired,
214 gracefulPowerOffTimerExpired,
215 powerOnRequest,
216 powerOffRequest,
217 powerCycleRequest,
218 resetRequest,
219 gracefulPowerOffRequest,
220 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700221 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700222};
223static std::string getEventName(Event event)
224{
225 switch (event)
226 {
227 case Event::psPowerOKAssert:
228 return "power supply power OK assert";
229 break;
230 case Event::psPowerOKDeAssert:
231 return "power supply power OK de-assert";
232 break;
233 case Event::sioPowerGoodAssert:
234 return "SIO power good assert";
235 break;
236 case Event::sioPowerGoodDeAssert:
237 return "SIO power good de-assert";
238 break;
239 case Event::sioS5Assert:
240 return "SIO S5 assert";
241 break;
242 case Event::sioS5DeAssert:
243 return "SIO S5 de-assert";
244 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700245 case Event::postCompleteAssert:
246 return "POST Complete assert";
247 break;
248 case Event::postCompleteDeAssert:
249 return "POST Complete de-assert";
250 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700251 case Event::powerButtonPressed:
252 return "power button pressed";
253 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700254 case Event::resetButtonPressed:
255 return "reset button pressed";
256 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700257 case Event::powerCycleTimerExpired:
258 return "power cycle timer expired";
259 break;
260 case Event::psPowerOKWatchdogTimerExpired:
261 return "power supply power OK watchdog timer expired";
262 break;
263 case Event::sioPowerGoodWatchdogTimerExpired:
264 return "SIO power good watchdog timer expired";
265 break;
266 case Event::gracefulPowerOffTimerExpired:
267 return "graceful power-off timer expired";
268 break;
269 case Event::powerOnRequest:
270 return "power-on request";
271 break;
272 case Event::powerOffRequest:
273 return "power-off request";
274 break;
275 case Event::powerCycleRequest:
276 return "power-cycle request";
277 break;
278 case Event::resetRequest:
279 return "reset request";
280 break;
281 case Event::gracefulPowerOffRequest:
282 return "graceful power-off request";
283 break;
284 case Event::gracefulPowerCycleRequest:
285 return "graceful power-cycle request";
286 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700287 case Event::warmResetDetected:
288 return "warm reset detected";
289 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700290 default:
291 return "unknown event: " + std::to_string(static_cast<int>(event));
292 break;
293 }
294}
295static void logEvent(const std::string_view stateHandler, const Event event)
296{
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700297 std::string logMsg{stateHandler};
298 logMsg += ": " + getEventName(event) + " event received";
299 phosphor::logging::log<phosphor::logging::level::INFO>(
300 logMsg.c_str(),
301 phosphor::logging::entry("EVENT=%s", getEventName(event).c_str()));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700302}
303
304// Power state handlers
305static void powerStateOn(const Event event);
306static void powerStateWaitForPSPowerOK(const Event event);
307static void powerStateWaitForSIOPowerGood(const Event event);
308static void powerStateFailedTransitionToOn(const Event event);
309static void powerStateOff(const Event event);
310static void powerStateTransitionToOff(const Event event);
311static void powerStateGracefulTransitionToOff(const Event event);
312static void powerStateCycleOff(const Event event);
313static void powerStateTransitionToCycleOff(const Event event);
314static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700315static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700316
317static std::function<void(const Event)> getPowerStateHandler(PowerState state)
318{
319 switch (state)
320 {
321 case PowerState::on:
322 return powerStateOn;
323 break;
324 case PowerState::waitForPSPowerOK:
325 return powerStateWaitForPSPowerOK;
326 break;
327 case PowerState::waitForSIOPowerGood:
328 return powerStateWaitForSIOPowerGood;
329 break;
330 case PowerState::failedTransitionToOn:
331 return powerStateFailedTransitionToOn;
332 break;
333 case PowerState::off:
334 return powerStateOff;
335 break;
336 case PowerState::transitionToOff:
337 return powerStateTransitionToOff;
338 break;
339 case PowerState::gracefulTransitionToOff:
340 return powerStateGracefulTransitionToOff;
341 break;
342 case PowerState::cycleOff:
343 return powerStateCycleOff;
344 break;
345 case PowerState::transitionToCycleOff:
346 return powerStateTransitionToCycleOff;
347 break;
348 case PowerState::gracefulTransitionToCycleOff:
349 return powerStateGracefulTransitionToCycleOff;
350 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700351 case PowerState::checkForWarmReset:
352 return powerStateCheckForWarmReset;
353 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700354 default:
355 return std::function<void(const Event)>{};
356 break;
357 }
358};
359
360static void sendPowerControlEvent(const Event event)
361{
362 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
363 if (handler == nullptr)
364 {
365 std::cerr << "Failed to find handler for power state: "
366 << static_cast<int>(powerState) << "\n";
367 return;
368 }
369 handler(event);
370}
371
372static uint64_t getCurrentTimeMs()
373{
374 struct timespec time = {};
375
376 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
377 {
378 return 0;
379 }
380 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
381 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
382
383 return currentTimeMs;
384}
385
386static constexpr std::string_view getHostState(const PowerState state)
387{
388 switch (state)
389 {
390 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700391 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700392 case PowerState::gracefulTransitionToCycleOff:
393 return "xyz.openbmc_project.State.Host.HostState.Running";
394 break;
395 case PowerState::waitForPSPowerOK:
396 case PowerState::waitForSIOPowerGood:
397 case PowerState::failedTransitionToOn:
398 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700399 case PowerState::transitionToOff:
400 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700401 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700402 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700403 return "xyz.openbmc_project.State.Host.HostState.Off";
404 break;
405 default:
406 return "";
407 break;
408 }
409};
410static constexpr std::string_view getChassisState(const PowerState state)
411{
412 switch (state)
413 {
414 case PowerState::on:
415 case PowerState::transitionToOff:
416 case PowerState::gracefulTransitionToOff:
417 case PowerState::transitionToCycleOff:
418 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700419 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700420 return "xyz.openbmc_project.State.Chassis.PowerState.On";
421 break;
422 case PowerState::waitForPSPowerOK:
423 case PowerState::waitForSIOPowerGood:
424 case PowerState::failedTransitionToOn:
425 case PowerState::off:
426 case PowerState::cycleOff:
427 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
428 break;
429 default:
430 return "";
431 break;
432 }
433};
434static void savePowerState(const PowerState state)
435{
436 powerStateSaveTimer.expires_after(
437 std::chrono::milliseconds(powerOffSaveTimeMs));
438 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
439 if (ec)
440 {
441 // operation_aborted is expected if timer is canceled before
442 // completion.
443 if (ec != boost::asio::error::operation_aborted)
444 {
445 std::cerr << "Power-state save async_wait failed: "
446 << ec.message() << "\n";
447 }
448 return;
449 }
450 std::ofstream powerStateStream(powerControlDir / powerStateFile);
451 powerStateStream << getChassisState(state);
452 });
453}
454static void setPowerState(const PowerState state)
455{
456 powerState = state;
457 logStateTransition(state);
458
459 hostIface->set_property("CurrentHostState",
460 std::string(getHostState(powerState)));
461
462 chassisIface->set_property("CurrentPowerState",
463 std::string(getChassisState(powerState)));
464 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
465
466 // Save the power state for the restore policy
467 savePowerState(state);
468}
469
470enum class RestartCause
471{
472 command,
473 resetButton,
474 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700475 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700476 powerPolicyOn,
477 powerPolicyRestore,
478 softReset,
479};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700480static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700481static std::string getRestartCause(RestartCause cause)
482{
483 switch (cause)
484 {
485 case RestartCause::command:
486 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
487 break;
488 case RestartCause::resetButton:
489 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
490 break;
491 case RestartCause::powerButton:
492 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
493 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700494 case RestartCause::watchdog:
495 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
496 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700497 case RestartCause::powerPolicyOn:
498 return "xyz.openbmc_project.State.Host.RestartCause."
499 "PowerPolicyAlwaysOn";
500 break;
501 case RestartCause::powerPolicyRestore:
502 return "xyz.openbmc_project.State.Host.RestartCause."
503 "PowerPolicyPreviousState";
504 break;
505 case RestartCause::softReset:
506 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
507 break;
508 default:
509 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
510 break;
511 }
512}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700513static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700514{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700515 // Add this to the set of causes for this restart
516 causeSet.insert(cause);
517}
518static void clearRestartCause()
519{
520 // Clear the set for the next restart
521 causeSet.clear();
522}
523static void setRestartCauseProperty(const std::string& cause)
524{
525 std::cerr << "RestartCause set to " << cause << "\n";
526 restartCauseIface->set_property("RestartCause", cause);
527}
Rashmi RV89f61312020-01-22 15:41:50 +0530528
529static void resetACBootProperty()
530{
531 if ((causeSet.contains(RestartCause::command)) ||
532 (causeSet.contains(RestartCause::softReset)))
533 {
534 conn->async_method_call(
535 [](boost::system::error_code ec) {
536 if (ec)
537 {
538 std::cerr << "failed to reset ACBoot property\n";
539 }
540 },
541 "xyz.openbmc_project.Settings",
542 "/xyz/openbmc_project/control/host0/ac_boot",
543 "org.freedesktop.DBus.Properties", "Set",
544 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
545 std::variant<std::string>{"False"});
546 }
547}
548
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700549static void setRestartCause()
550{
551 // Determine the actual restart cause based on the set of causes
552 std::string restartCause =
553 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
554 if (causeSet.contains(RestartCause::watchdog))
555 {
556 restartCause = getRestartCause(RestartCause::watchdog);
557 }
558 else if (causeSet.contains(RestartCause::command))
559 {
560 restartCause = getRestartCause(RestartCause::command);
561 }
562 else if (causeSet.contains(RestartCause::resetButton))
563 {
564 restartCause = getRestartCause(RestartCause::resetButton);
565 }
566 else if (causeSet.contains(RestartCause::powerButton))
567 {
568 restartCause = getRestartCause(RestartCause::powerButton);
569 }
570 else if (causeSet.contains(RestartCause::powerPolicyOn))
571 {
572 restartCause = getRestartCause(RestartCause::powerPolicyOn);
573 }
574 else if (causeSet.contains(RestartCause::powerPolicyRestore))
575 {
576 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
577 }
578 else if (causeSet.contains(RestartCause::softReset))
579 {
580 restartCause = getRestartCause(RestartCause::softReset);
581 }
582
583 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700584}
585
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700586static void systemPowerGoodFailedLog()
587{
588 sd_journal_send(
589 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
590 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
591 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
592 sioPowerGoodWatchdogTimeMs, NULL);
593}
594
595static void psPowerOKFailedLog()
596{
597 sd_journal_send(
598 "MESSAGE=PowerControl: power supply power good failed to assert",
599 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
600 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
601 psPowerOKWatchdogTimeMs, NULL);
602}
603
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700604static void powerRestorePolicyLog()
605{
606 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
607 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
608 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
609}
610
611static void powerButtonPressLog()
612{
613 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
614 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
615 "OpenBMC.0.1.PowerButtonPressed", NULL);
616}
617
618static void resetButtonPressLog()
619{
620 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
621 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
622 "OpenBMC.0.1.ResetButtonPressed", NULL);
623}
624
625static void nmiButtonPressLog()
626{
627 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
628 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
629 "OpenBMC.0.1.NMIButtonPressed", NULL);
630}
631
632static void nmiDiagIntLog()
633{
634 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
635 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
636 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
637}
638
639static int initializePowerStateStorage()
640{
641 // create the power control directory if it doesn't exist
642 std::error_code ec;
643 if (!(std::filesystem::create_directories(powerControlDir, ec)))
644 {
645 if (ec.value() != 0)
646 {
647 std::cerr << "failed to create " << powerControlDir << ": "
648 << ec.message() << "\n";
649 return -1;
650 }
651 }
652 // Create the power state file if it doesn't exist
653 if (!std::filesystem::exists(powerControlDir / powerStateFile))
654 {
655 std::ofstream powerStateStream(powerControlDir / powerStateFile);
656 powerStateStream << getChassisState(powerState);
657 }
658 return 0;
659}
660
661static bool wasPowerDropped()
662{
663 std::ifstream powerStateStream(powerControlDir / powerStateFile);
664 if (!powerStateStream.is_open())
665 {
666 std::cerr << "Failed to open power state file\n";
667 return false;
668 }
669
670 std::string state;
671 std::getline(powerStateStream, state);
672 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
673}
674
675static void invokePowerRestorePolicy(const std::string& policy)
676{
677 // Async events may call this twice, but we only want to run once
678 static bool policyInvoked = false;
679 if (policyInvoked)
680 {
681 return;
682 }
683 policyInvoked = true;
684
685 std::cerr << "Power restore delay expired, invoking " << policy << "\n";
686 if (policy ==
687 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
688 {
689 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700690 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700691 }
692 else if (policy == "xyz.openbmc_project.Control.Power.RestorePolicy."
693 "Policy.Restore")
694 {
695 if (wasPowerDropped())
696 {
697 std::cerr << "Power was dropped, restoring Host On state\n";
698 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700699 setRestartCauseProperty(
700 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700701 }
702 else
703 {
704 std::cerr << "No power drop, restoring Host Off state\n";
705 }
706 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -0700707 // We're done with the previous power state for the restore policy, so store
708 // the current state
709 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700710}
711
712static void powerRestorePolicyDelay(int delay)
713{
714 // Async events may call this twice, but we only want to run once
715 static bool delayStarted = false;
716 if (delayStarted)
717 {
718 return;
719 }
720 delayStarted = true;
721 // Calculate the delay from now to meet the requested delay
722 // Subtract the approximate uboot time
723 static constexpr const int ubootSeconds = 20;
724 delay -= ubootSeconds;
725 // Subtract the time since boot
726 struct sysinfo info = {};
727 if (sysinfo(&info) == 0)
728 {
729 delay -= info.uptime;
730 }
731 // 0 is the minimum delay
732 delay = std::max(delay, 0);
733
734 static boost::asio::steady_timer powerRestorePolicyTimer(io);
735 powerRestorePolicyTimer.expires_after(std::chrono::seconds(delay));
736 std::cerr << "Power restore delay of " << delay << " seconds started\n";
737 powerRestorePolicyTimer.async_wait([](const boost::system::error_code ec) {
738 if (ec)
739 {
740 // operation_aborted is expected if timer is canceled before
741 // completion.
742 if (ec != boost::asio::error::operation_aborted)
743 {
744 std::cerr << "power restore policy async_wait failed: "
745 << ec.message() << "\n";
746 }
747 return;
748 }
749 // Get Power Restore Policy
750 // In case PowerRestorePolicy is not available, set a match for it
751 static std::unique_ptr<sdbusplus::bus::match::match>
752 powerRestorePolicyMatch = std::make_unique<
753 sdbusplus::bus::match::match>(
754 *conn,
755 "type='signal',interface='org.freedesktop.DBus.Properties',"
756 "member='PropertiesChanged',arg0namespace='xyz.openbmc_"
757 "project.Control.Power.RestorePolicy'",
758 [](sdbusplus::message::message& msg) {
759 std::string interfaceName;
760 boost::container::flat_map<std::string,
761 std::variant<std::string>>
762 propertiesChanged;
763 std::string policy;
764 try
765 {
766 msg.read(interfaceName, propertiesChanged);
767 policy = std::get<std::string>(
768 propertiesChanged.begin()->second);
769 }
770 catch (std::exception& e)
771 {
772 std::cerr
773 << "Unable to read power restore policy value\n";
774 powerRestorePolicyMatch.reset();
775 return;
776 }
777 invokePowerRestorePolicy(policy);
778 powerRestorePolicyMatch.reset();
779 });
780
781 // Check if it's already on DBus
782 conn->async_method_call(
783 [](boost::system::error_code ec,
784 const std::variant<std::string>& policyProperty) {
785 if (ec)
786 {
787 return;
788 }
789 powerRestorePolicyMatch.reset();
790 const std::string* policy =
791 std::get_if<std::string>(&policyProperty);
792 if (policy == nullptr)
793 {
794 std::cerr << "Unable to read power restore policy value\n";
795 return;
796 }
797 invokePowerRestorePolicy(*policy);
798 },
799 "xyz.openbmc_project.Settings",
800 "/xyz/openbmc_project/control/host0/power_restore_policy",
801 "org.freedesktop.DBus.Properties", "Get",
802 "xyz.openbmc_project.Control.Power.RestorePolicy",
803 "PowerRestorePolicy");
804 });
805}
806
807static void powerRestorePolicyStart()
808{
809 std::cerr << "Power restore policy started\n";
810 powerRestorePolicyLog();
811
812 // Get the desired delay time
813 // In case PowerRestoreDelay is not available, set a match for it
814 static std::unique_ptr<sdbusplus::bus::match::match>
815 powerRestoreDelayMatch = std::make_unique<sdbusplus::bus::match::match>(
816 *conn,
817 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
818 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Control."
819 "Power.RestoreDelay'",
820 [](sdbusplus::message::message& msg) {
821 std::string interfaceName;
822 boost::container::flat_map<std::string, std::variant<uint16_t>>
823 propertiesChanged;
824 int delay = 0;
825 try
826 {
827 msg.read(interfaceName, propertiesChanged);
828 delay =
829 std::get<uint16_t>(propertiesChanged.begin()->second);
830 }
831 catch (std::exception& e)
832 {
833 std::cerr << "Unable to read power restore delay value\n";
834 powerRestoreDelayMatch.reset();
835 return;
836 }
837 powerRestorePolicyDelay(delay);
838 powerRestoreDelayMatch.reset();
839 });
840
841 // Check if it's already on DBus
842 conn->async_method_call(
843 [](boost::system::error_code ec,
844 const std::variant<uint16_t>& delayProperty) {
845 if (ec)
846 {
847 return;
848 }
849 powerRestoreDelayMatch.reset();
850 const uint16_t* delay = std::get_if<uint16_t>(&delayProperty);
851 if (delay == nullptr)
852 {
853 std::cerr << "Unable to read power restore delay value\n";
854 return;
855 }
856 powerRestorePolicyDelay(*delay);
857 },
858 "xyz.openbmc_project.Settings",
859 "/xyz/openbmc_project/control/power_restore_delay",
860 "org.freedesktop.DBus.Properties", "Get",
861 "xyz.openbmc_project.Control.Power.RestoreDelay", "PowerRestoreDelay");
862}
863
864static void powerRestorePolicyCheck()
865{
866 // In case ACBoot is not available, set a match for it
867 static std::unique_ptr<sdbusplus::bus::match::match> acBootMatch =
868 std::make_unique<sdbusplus::bus::match::match>(
869 *conn,
870 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
871 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Common."
872 "ACBoot'",
873 [](sdbusplus::message::message& msg) {
874 std::string interfaceName;
875 boost::container::flat_map<std::string,
876 std::variant<std::string>>
877 propertiesChanged;
878 std::string acBoot;
879 try
880 {
881 msg.read(interfaceName, propertiesChanged);
882 acBoot = std::get<std::string>(
883 propertiesChanged.begin()->second);
884 }
885 catch (std::exception& e)
886 {
887 std::cerr << "Unable to read AC Boot status\n";
888 acBootMatch.reset();
889 return;
890 }
891 if (acBoot == "Unknown")
892 {
893 return;
894 }
895 if (acBoot == "True")
896 {
897 // Start the Power Restore policy
898 powerRestorePolicyStart();
899 }
900 acBootMatch.reset();
901 });
902
903 // Check if it's already on DBus
904 conn->async_method_call(
905 [](boost::system::error_code ec,
906 const std::variant<std::string>& acBootProperty) {
907 if (ec)
908 {
909 return;
910 }
911 const std::string* acBoot =
912 std::get_if<std::string>(&acBootProperty);
913 if (acBoot == nullptr)
914 {
915 std::cerr << "Unable to read AC Boot status\n";
916 return;
917 }
918 if (*acBoot == "Unknown")
919 {
920 return;
921 }
922 if (*acBoot == "True")
923 {
924 // Start the Power Restore policy
925 powerRestorePolicyStart();
926 }
927 acBootMatch.reset();
928 },
929 "xyz.openbmc_project.Settings",
930 "/xyz/openbmc_project/control/host0/ac_boot",
931 "org.freedesktop.DBus.Properties", "Get",
932 "xyz.openbmc_project.Common.ACBoot", "ACBoot");
933}
934
935static bool requestGPIOEvents(
936 const std::string& name, const std::function<void()>& handler,
937 gpiod::line& gpioLine,
938 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
939{
940 // Find the GPIO line
941 gpioLine = gpiod::find_line(name);
942 if (!gpioLine)
943 {
944 std::cerr << "Failed to find the " << name << " line\n";
945 return false;
946 }
947
948 try
949 {
950 gpioLine.request(
951 {"power-control", gpiod::line_request::EVENT_BOTH_EDGES});
952 }
953 catch (std::exception&)
954 {
955 std::cerr << "Failed to request events for " << name << "\n";
956 return false;
957 }
958
959 int gpioLineFd = gpioLine.event_get_fd();
960 if (gpioLineFd < 0)
961 {
962 std::cerr << "Failed to get " << name << " fd\n";
963 return false;
964 }
965
966 gpioEventDescriptor.assign(gpioLineFd);
967
968 gpioEventDescriptor.async_wait(
969 boost::asio::posix::stream_descriptor::wait_read,
970 [&name, handler](const boost::system::error_code ec) {
971 if (ec)
972 {
973 std::cerr << name << " fd handler error: " << ec.message()
974 << "\n";
975 // TODO: throw here to force power-control to restart?
976 return;
977 }
978 handler();
979 });
980 return true;
981}
982
983static bool setGPIOOutput(const std::string& name, const int value,
984 gpiod::line& gpioLine)
985{
986 // Find the GPIO line
987 gpioLine = gpiod::find_line(name);
988 if (!gpioLine)
989 {
990 std::cerr << "Failed to find the " << name << " line.\n";
991 return false;
992 }
993
994 // Request GPIO output to specified value
995 try
996 {
997 gpioLine.request({__FUNCTION__, gpiod::line_request::DIRECTION_OUTPUT},
998 value);
999 }
1000 catch (std::exception&)
1001 {
1002 std::cerr << "Failed to request " << name << " output\n";
1003 return false;
1004 }
1005
1006 std::cerr << name << " set to " << std::to_string(value) << "\n";
1007 return true;
1008}
1009
1010static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1011 const std::string& name, const int value,
1012 const int durationMs)
1013{
1014 // Set the masked GPIO line to the specified value
1015 maskedGPIOLine.set_value(value);
1016 std::cerr << name << " set to " << std::to_string(value) << "\n";
1017 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
1018 gpioAssertTimer.async_wait(
1019 [maskedGPIOLine, value, name](const boost::system::error_code ec) {
1020 // Set the masked GPIO line back to the opposite value
1021 maskedGPIOLine.set_value(!value);
1022 std::cerr << name << " released\n";
1023 if (ec)
1024 {
1025 // operation_aborted is expected if timer is canceled before
1026 // completion.
1027 if (ec != boost::asio::error::operation_aborted)
1028 {
1029 std::cerr << name << " async_wait failed: " + ec.message()
1030 << "\n";
1031 }
1032 }
1033 });
1034 return 0;
1035}
1036
1037static int setGPIOOutputForMs(const std::string& name, const int value,
1038 const int durationMs)
1039{
1040 // If the requested GPIO is masked, use the mask line to set the output
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001041 if (powerButtonMask && name == power_control::powerOutName)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001042 {
1043 return setMaskedGPIOOutputForMs(powerButtonMask, name, value,
1044 durationMs);
1045 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001046 if (resetButtonMask && name == power_control::resetOutName)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001047 {
1048 return setMaskedGPIOOutputForMs(resetButtonMask, name, value,
1049 durationMs);
1050 }
1051
1052 // No mask set, so request and set the GPIO normally
1053 gpiod::line gpioLine;
1054 if (!setGPIOOutput(name, value, gpioLine))
1055 {
1056 return -1;
1057 }
1058 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
1059 gpioAssertTimer.async_wait(
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001060 [gpioLine, value, name](const boost::system::error_code ec) {
1061 // Set the GPIO line back to the opposite value
1062 gpioLine.set_value(!value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001063 std::cerr << name << " released\n";
1064 if (ec)
1065 {
1066 // operation_aborted is expected if timer is canceled before
1067 // completion.
1068 if (ec != boost::asio::error::operation_aborted)
1069 {
1070 std::cerr << name << " async_wait failed: " << ec.message()
1071 << "\n";
1072 }
1073 }
1074 });
1075 return 0;
1076}
1077
1078static void powerOn()
1079{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001080 setGPIOOutputForMs(power_control::powerOutName, 0, powerPulseTimeMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001081}
1082
1083static void gracefulPowerOff()
1084{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001085 setGPIOOutputForMs(power_control::powerOutName, 0, powerPulseTimeMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001086}
1087
1088static void forcePowerOff()
1089{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001090 if (setGPIOOutputForMs(power_control::powerOutName, 0,
1091 forceOffPulseTimeMs) < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001092 {
1093 return;
1094 }
1095
1096 // If the force off timer expires, then the PCH power-button override
1097 // failed, so attempt the Unconditional Powerdown SMBus command.
1098 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1099 if (ec)
1100 {
1101 // operation_aborted is expected if timer is canceled before
1102 // completion.
1103 if (ec != boost::asio::error::operation_aborted)
1104 {
1105 std::cerr << "Force power off async_wait failed: "
1106 << ec.message() << "\n";
1107 }
1108 return;
1109 }
1110 std::cerr << "PCH Power-button override failed. Issuing Unconditional "
1111 "Powerdown SMBus command.\n";
1112 const static constexpr size_t pchDevBusAddress = 3;
1113 const static constexpr size_t pchDevSlaveAddress = 0x44;
1114 const static constexpr size_t pchCmdReg = 0;
1115 const static constexpr size_t pchPowerDownCmd = 0x02;
1116 if (i2cSet(pchDevBusAddress, pchDevSlaveAddress, pchCmdReg,
1117 pchPowerDownCmd) < 0)
1118 {
1119 std::cerr << "Unconditional Powerdown command failed! Not sure "
1120 "what to do now.\n";
1121 }
1122 });
1123}
1124
1125static void reset()
1126{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001127 setGPIOOutputForMs(power_control::resetOutName, 0, resetPulseTimeMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001128}
1129
1130static void gracefulPowerOffTimerStart()
1131{
1132 std::cerr << "Graceful power-off timer started\n";
1133 gracefulPowerOffTimer.expires_after(
1134 std::chrono::milliseconds(gracefulPowerOffTimeMs));
1135 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1136 if (ec)
1137 {
1138 // operation_aborted is expected if timer is canceled before
1139 // completion.
1140 if (ec != boost::asio::error::operation_aborted)
1141 {
1142 std::cerr << "Graceful power-off async_wait failed: "
1143 << ec.message() << "\n";
1144 }
1145 std::cerr << "Graceful power-off timer canceled\n";
1146 return;
1147 }
1148 std::cerr << "Graceful power-off timer completed\n";
1149 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1150 });
1151}
1152
1153static void powerCycleTimerStart()
1154{
1155 std::cerr << "Power-cycle timer started\n";
1156 powerCycleTimer.expires_after(std::chrono::milliseconds(powerCycleTimeMs));
1157 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1158 if (ec)
1159 {
1160 // operation_aborted is expected if timer is canceled before
1161 // completion.
1162 if (ec != boost::asio::error::operation_aborted)
1163 {
1164 std::cerr << "Power-cycle async_wait failed: " << ec.message()
1165 << "\n";
1166 }
1167 std::cerr << "Power-cycle timer canceled\n";
1168 return;
1169 }
1170 std::cerr << "Power-cycle timer completed\n";
1171 sendPowerControlEvent(Event::powerCycleTimerExpired);
1172 });
1173}
1174
1175static void psPowerOKWatchdogTimerStart()
1176{
1177 std::cerr << "power supply power OK watchdog timer started\n";
1178 psPowerOKWatchdogTimer.expires_after(
1179 std::chrono::milliseconds(psPowerOKWatchdogTimeMs));
1180 psPowerOKWatchdogTimer.async_wait(
1181 [](const boost::system::error_code ec) {
1182 if (ec)
1183 {
1184 // operation_aborted is expected if timer is canceled before
1185 // completion.
1186 if (ec != boost::asio::error::operation_aborted)
1187 {
1188 std::cerr
1189 << "power supply power OK watchdog async_wait failed: "
1190 << ec.message() << "\n";
1191 }
1192 std::cerr << "power supply power OK watchdog timer canceled\n";
1193 return;
1194 }
1195 std::cerr << "power supply power OK watchdog timer expired\n";
1196 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1197 });
1198}
1199
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001200static void warmResetCheckTimerStart()
1201{
1202 std::cerr << "Warm reset check timer started\n";
1203 warmResetCheckTimer.expires_after(
1204 std::chrono::milliseconds(warmResetCheckTimeMs));
1205 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1206 if (ec)
1207 {
1208 // operation_aborted is expected if timer is canceled before
1209 // completion.
1210 if (ec != boost::asio::error::operation_aborted)
1211 {
1212 std::cerr << "Warm reset check async_wait failed: "
1213 << ec.message() << "\n";
1214 }
1215 std::cerr << "Warm reset check timer canceled\n";
1216 return;
1217 }
1218 std::cerr << "Warm reset check timer completed\n";
1219 sendPowerControlEvent(Event::warmResetDetected);
1220 });
1221}
1222
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001223static void pohCounterTimerStart()
1224{
1225 std::cerr << "POH timer started\n";
1226 // Set the time-out as 1 hour, to align with POH command in ipmid
1227 pohCounterTimer.expires_after(std::chrono::hours(1));
1228 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1229 if (ec)
1230 {
1231 // operation_aborted is expected if timer is canceled before
1232 // completion.
1233 if (ec != boost::asio::error::operation_aborted)
1234 {
1235 std::cerr << "POH timer async_wait failed: " << ec.message()
1236 << "\n";
1237 }
1238 std::cerr << "POH timer canceled\n";
1239 return;
1240 }
1241
1242 if (getHostState(powerState) !=
1243 "xyz.openbmc_project.State.Host.HostState.Running")
1244 {
1245 return;
1246 }
1247
1248 conn->async_method_call(
1249 [](boost::system::error_code ec,
1250 const std::variant<uint32_t>& pohCounterProperty) {
1251 if (ec)
1252 {
1253 std::cerr << "error to get poh counter\n";
1254 return;
1255 }
1256 const uint32_t* pohCounter =
1257 std::get_if<uint32_t>(&pohCounterProperty);
1258 if (pohCounter == nullptr)
1259 {
1260 std::cerr << "unable to read poh counter\n";
1261 return;
1262 }
1263
1264 conn->async_method_call(
1265 [](boost::system::error_code ec) {
1266 if (ec)
1267 {
1268 std::cerr << "failed to set poh counter\n";
1269 }
1270 },
1271 "xyz.openbmc_project.Settings",
1272 "/xyz/openbmc_project/state/chassis0",
1273 "org.freedesktop.DBus.Properties", "Set",
1274 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1275 std::variant<uint32_t>(*pohCounter + 1));
1276 },
1277 "xyz.openbmc_project.Settings",
1278 "/xyz/openbmc_project/state/chassis0",
1279 "org.freedesktop.DBus.Properties", "Get",
1280 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1281
1282 pohCounterTimerStart();
1283 });
1284}
1285
1286static void currentHostStateMonitor()
1287{
Yong Li8d660212019-12-27 10:18:10 +08001288 if (getHostState(powerState) ==
1289 "xyz.openbmc_project.State.Host.HostState.Running")
1290 {
1291 pohCounterTimerStart();
1292 // Clear the restart cause set for the next restart
1293 clearRestartCause();
1294 }
1295 else
1296 {
1297 pohCounterTimer.cancel();
1298 // Set the restart cause set for this restart
1299 setRestartCause();
1300 }
1301
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001302 static auto match = sdbusplus::bus::match::match(
1303 *conn,
1304 "type='signal',member='PropertiesChanged', "
1305 "interface='org.freedesktop.DBus.Properties', "
1306 "arg0namespace='xyz.openbmc_project.State.Host'",
1307 [](sdbusplus::message::message& message) {
1308 std::string intfName;
1309 std::map<std::string, std::variant<std::string>> properties;
1310
1311 message.read(intfName, properties);
1312
1313 std::variant<std::string> currentHostState;
1314
1315 try
1316 {
1317 currentHostState = properties.at("CurrentHostState");
1318 }
1319 catch (const std::out_of_range& e)
1320 {
1321 std::cerr << "Error in finding CurrentHostState property\n";
1322
1323 return;
1324 }
1325
1326 if (std::get<std::string>(currentHostState) ==
1327 "xyz.openbmc_project.State.Host.HostState.Running")
1328 {
1329 pohCounterTimerStart();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001330 // Clear the restart cause set for the next restart
1331 clearRestartCause();
Yong Li8d660212019-12-27 10:18:10 +08001332 sd_journal_send("MESSAGE=Host system DC power is on",
1333 "PRIORITY=%i", LOG_INFO,
1334 "REDFISH_MESSAGE_ID=%s",
1335 "OpenBMC.0.1.DCPowerOn", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001336 }
1337 else
1338 {
1339 pohCounterTimer.cancel();
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301340 // POST_COMPLETE GPIO event is not working in some platforms
1341 // when power state is changed to OFF. This resulted in
1342 // 'OperatingSystemState' to stay at 'Standby', even though
1343 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1344 // if HostState is trurned to OFF.
1345 osIface->set_property("OperatingSystemState",
1346 std::string("Inactive"));
1347
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001348 // Set the restart cause set for this restart
1349 setRestartCause();
Rashmi RV89f61312020-01-22 15:41:50 +05301350 resetACBootProperty();
Yong Li8d660212019-12-27 10:18:10 +08001351 sd_journal_send("MESSAGE=Host system DC power is off",
1352 "PRIORITY=%i", LOG_INFO,
1353 "REDFISH_MESSAGE_ID=%s",
1354 "OpenBMC.0.1.DCPowerOff", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001355 }
1356 });
1357}
1358
1359static void sioPowerGoodWatchdogTimerStart()
1360{
1361 std::cerr << "SIO power good watchdog timer started\n";
1362 sioPowerGoodWatchdogTimer.expires_after(
1363 std::chrono::milliseconds(sioPowerGoodWatchdogTimeMs));
1364 sioPowerGoodWatchdogTimer.async_wait(
1365 [](const boost::system::error_code ec) {
1366 if (ec)
1367 {
1368 // operation_aborted is expected if timer is canceled before
1369 // completion.
1370 if (ec != boost::asio::error::operation_aborted)
1371 {
1372 std::cerr << "SIO power good watchdog async_wait failed: "
1373 << ec.message() << "\n";
1374 }
1375 std::cerr << "SIO power good watchdog timer canceled\n";
1376 return;
1377 }
1378 std::cerr << "SIO power good watchdog timer completed\n";
1379 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1380 });
1381}
1382
1383static void powerStateOn(const Event event)
1384{
1385 logEvent(__FUNCTION__, event);
1386 switch (event)
1387 {
1388 case Event::psPowerOKDeAssert:
1389 setPowerState(PowerState::off);
1390 // DC power is unexpectedly lost, beep
1391 beep(beepPowerFail);
1392 break;
1393 case Event::sioS5Assert:
1394 setPowerState(PowerState::transitionToOff);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001395 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001396 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001397 case Event::postCompleteDeAssert:
1398 setPowerState(PowerState::checkForWarmReset);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001399 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001400 warmResetCheckTimerStart();
1401 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001402 case Event::powerButtonPressed:
1403 setPowerState(PowerState::gracefulTransitionToOff);
1404 gracefulPowerOffTimerStart();
1405 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001406 case Event::resetButtonPressed:
1407 setPowerState(PowerState::checkForWarmReset);
1408 warmResetCheckTimerStart();
1409 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001410 case Event::powerOffRequest:
1411 setPowerState(PowerState::transitionToOff);
1412 forcePowerOff();
1413 break;
1414 case Event::gracefulPowerOffRequest:
1415 setPowerState(PowerState::gracefulTransitionToOff);
1416 gracefulPowerOffTimerStart();
1417 gracefulPowerOff();
1418 break;
1419 case Event::powerCycleRequest:
1420 setPowerState(PowerState::transitionToCycleOff);
1421 forcePowerOff();
1422 break;
1423 case Event::gracefulPowerCycleRequest:
1424 setPowerState(PowerState::gracefulTransitionToCycleOff);
1425 gracefulPowerOffTimerStart();
1426 gracefulPowerOff();
1427 break;
1428 case Event::resetRequest:
1429 reset();
1430 break;
1431 default:
1432 std::cerr << "No action taken.\n";
1433 break;
1434 }
1435}
1436
1437static void powerStateWaitForPSPowerOK(const Event event)
1438{
1439 logEvent(__FUNCTION__, event);
1440 switch (event)
1441 {
1442 case Event::psPowerOKAssert:
1443 // Cancel any GPIO assertions held during the transition
1444 gpioAssertTimer.cancel();
1445 psPowerOKWatchdogTimer.cancel();
1446 sioPowerGoodWatchdogTimerStart();
1447 setPowerState(PowerState::waitForSIOPowerGood);
1448 break;
1449 case Event::psPowerOKWatchdogTimerExpired:
1450 setPowerState(PowerState::failedTransitionToOn);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001451 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001452 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001453 case Event::sioPowerGoodAssert:
1454 psPowerOKWatchdogTimer.cancel();
1455 setPowerState(PowerState::on);
1456 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001457 default:
1458 std::cerr << "No action taken.\n";
1459 break;
1460 }
1461}
1462
1463static void powerStateWaitForSIOPowerGood(const Event event)
1464{
1465 logEvent(__FUNCTION__, event);
1466 switch (event)
1467 {
1468 case Event::sioPowerGoodAssert:
1469 sioPowerGoodWatchdogTimer.cancel();
1470 setPowerState(PowerState::on);
1471 break;
1472 case Event::sioPowerGoodWatchdogTimerExpired:
1473 setPowerState(PowerState::failedTransitionToOn);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001474 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001475 forcePowerOff();
1476 break;
1477 default:
1478 std::cerr << "No action taken.\n";
1479 break;
1480 }
1481}
1482
1483static void powerStateFailedTransitionToOn(const Event event)
1484{
1485 logEvent(__FUNCTION__, event);
1486 switch (event)
1487 {
1488 case Event::psPowerOKAssert:
1489 // We're in a failure state, so don't allow the system to turn on
1490 // without a user request
1491 forcePowerOff();
1492 break;
1493 case Event::psPowerOKDeAssert:
1494 // Cancel any GPIO assertions held during the transition
1495 gpioAssertTimer.cancel();
1496 break;
1497 case Event::powerButtonPressed:
1498 psPowerOKWatchdogTimerStart();
1499 setPowerState(PowerState::waitForPSPowerOK);
1500 break;
1501 case Event::powerOnRequest:
1502 psPowerOKWatchdogTimerStart();
1503 setPowerState(PowerState::waitForPSPowerOK);
1504 powerOn();
1505 break;
1506 default:
1507 std::cerr << "No action taken.\n";
1508 break;
1509 }
1510}
1511
1512static void powerStateOff(const Event event)
1513{
1514 logEvent(__FUNCTION__, event);
1515 switch (event)
1516 {
1517 case Event::psPowerOKAssert:
1518 setPowerState(PowerState::waitForSIOPowerGood);
1519 break;
1520 case Event::sioS5DeAssert:
1521 setPowerState(PowerState::waitForPSPowerOK);
1522 break;
1523 case Event::powerButtonPressed:
1524 psPowerOKWatchdogTimerStart();
1525 setPowerState(PowerState::waitForPSPowerOK);
1526 break;
1527 case Event::powerOnRequest:
1528 psPowerOKWatchdogTimerStart();
1529 setPowerState(PowerState::waitForPSPowerOK);
1530 powerOn();
1531 break;
1532 default:
1533 std::cerr << "No action taken.\n";
1534 break;
1535 }
1536}
1537
1538static void powerStateTransitionToOff(const Event event)
1539{
1540 logEvent(__FUNCTION__, event);
1541 switch (event)
1542 {
1543 case Event::psPowerOKDeAssert:
1544 // Cancel any GPIO assertions held during the transition
1545 gpioAssertTimer.cancel();
1546 setPowerState(PowerState::off);
1547 break;
1548 default:
1549 std::cerr << "No action taken.\n";
1550 break;
1551 }
1552}
1553
1554static void powerStateGracefulTransitionToOff(const Event event)
1555{
1556 logEvent(__FUNCTION__, event);
1557 switch (event)
1558 {
1559 case Event::psPowerOKDeAssert:
1560 gracefulPowerOffTimer.cancel();
1561 setPowerState(PowerState::off);
1562 break;
1563 case Event::gracefulPowerOffTimerExpired:
1564 setPowerState(PowerState::on);
1565 break;
1566 default:
1567 std::cerr << "No action taken.\n";
1568 break;
1569 }
1570}
1571
1572static void powerStateCycleOff(const Event event)
1573{
1574 logEvent(__FUNCTION__, event);
1575 switch (event)
1576 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001577 case Event::psPowerOKAssert:
1578 powerCycleTimer.cancel();
1579 setPowerState(PowerState::waitForSIOPowerGood);
1580 break;
1581 case Event::sioS5DeAssert:
1582 powerCycleTimer.cancel();
1583 setPowerState(PowerState::waitForPSPowerOK);
1584 break;
1585 case Event::powerButtonPressed:
1586 powerCycleTimer.cancel();
1587 psPowerOKWatchdogTimerStart();
1588 setPowerState(PowerState::waitForPSPowerOK);
1589 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001590 case Event::powerCycleTimerExpired:
1591 psPowerOKWatchdogTimerStart();
1592 setPowerState(PowerState::waitForPSPowerOK);
1593 powerOn();
1594 break;
1595 default:
1596 std::cerr << "No action taken.\n";
1597 break;
1598 }
1599}
1600
1601static void powerStateTransitionToCycleOff(const Event event)
1602{
1603 logEvent(__FUNCTION__, event);
1604 switch (event)
1605 {
1606 case Event::psPowerOKDeAssert:
1607 // Cancel any GPIO assertions held during the transition
1608 gpioAssertTimer.cancel();
1609 setPowerState(PowerState::cycleOff);
1610 powerCycleTimerStart();
1611 break;
1612 default:
1613 std::cerr << "No action taken.\n";
1614 break;
1615 }
1616}
1617
1618static void powerStateGracefulTransitionToCycleOff(const Event event)
1619{
1620 logEvent(__FUNCTION__, event);
1621 switch (event)
1622 {
1623 case Event::psPowerOKDeAssert:
1624 gracefulPowerOffTimer.cancel();
1625 setPowerState(PowerState::cycleOff);
1626 powerCycleTimerStart();
1627 break;
1628 case Event::gracefulPowerOffTimerExpired:
1629 setPowerState(PowerState::on);
1630 break;
1631 default:
1632 std::cerr << "No action taken.\n";
1633 break;
1634 }
1635}
1636
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001637static void powerStateCheckForWarmReset(const Event event)
1638{
1639 logEvent(__FUNCTION__, event);
1640 switch (event)
1641 {
1642 case Event::sioS5Assert:
1643 warmResetCheckTimer.cancel();
1644 setPowerState(PowerState::transitionToOff);
1645 break;
1646 case Event::warmResetDetected:
1647 setPowerState(PowerState::on);
1648 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001649 case Event::psPowerOKDeAssert:
1650 warmResetCheckTimer.cancel();
1651 setPowerState(PowerState::off);
1652 // DC power is unexpectedly lost, beep
1653 beep(beepPowerFail);
1654 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001655 default:
1656 std::cerr << "No action taken.\n";
1657 break;
1658 }
1659}
1660
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001661static void psPowerOKHandler()
1662{
1663 gpiod::line_event gpioLineEvent = psPowerOKLine.event_read();
1664
1665 Event powerControlEvent =
1666 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
1667 ? Event::psPowerOKAssert
1668 : Event::psPowerOKDeAssert;
1669
1670 sendPowerControlEvent(powerControlEvent);
1671 psPowerOKEvent.async_wait(
1672 boost::asio::posix::stream_descriptor::wait_read,
1673 [](const boost::system::error_code ec) {
1674 if (ec)
1675 {
1676 std::cerr << "power supply power OK handler error: "
1677 << ec.message() << "\n";
1678 return;
1679 }
1680 psPowerOKHandler();
1681 });
1682}
1683
1684static void sioPowerGoodHandler()
1685{
1686 gpiod::line_event gpioLineEvent = sioPowerGoodLine.event_read();
1687
1688 Event powerControlEvent =
1689 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
1690 ? Event::sioPowerGoodAssert
1691 : Event::sioPowerGoodDeAssert;
1692
1693 sendPowerControlEvent(powerControlEvent);
1694 sioPowerGoodEvent.async_wait(
1695 boost::asio::posix::stream_descriptor::wait_read,
1696 [](const boost::system::error_code ec) {
1697 if (ec)
1698 {
1699 std::cerr << "SIO power good handler error: " << ec.message()
1700 << "\n";
1701 return;
1702 }
1703 sioPowerGoodHandler();
1704 });
1705}
1706
1707static void sioOnControlHandler()
1708{
1709 gpiod::line_event gpioLineEvent = sioOnControlLine.event_read();
1710
1711 bool sioOnControl =
1712 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE;
1713 std::cerr << "SIO_ONCONTROL value changed: " << sioOnControl << "\n";
1714 sioOnControlEvent.async_wait(
1715 boost::asio::posix::stream_descriptor::wait_read,
1716 [](const boost::system::error_code ec) {
1717 if (ec)
1718 {
1719 std::cerr << "SIO ONCONTROL handler error: " << ec.message()
1720 << "\n";
1721 return;
1722 }
1723 sioOnControlHandler();
1724 });
1725}
1726
1727static void sioS5Handler()
1728{
1729 gpiod::line_event gpioLineEvent = sioS5Line.event_read();
1730
1731 Event powerControlEvent =
1732 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE
1733 ? Event::sioS5Assert
1734 : Event::sioS5DeAssert;
1735
1736 sendPowerControlEvent(powerControlEvent);
1737 sioS5Event.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1738 [](const boost::system::error_code ec) {
1739 if (ec)
1740 {
1741 std::cerr << "SIO S5 handler error: "
1742 << ec.message() << "\n";
1743 return;
1744 }
1745 sioS5Handler();
1746 });
1747}
1748
1749static void powerButtonHandler()
1750{
1751 gpiod::line_event gpioLineEvent = powerButtonLine.event_read();
1752
1753 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1754 {
1755 powerButtonPressLog();
1756 powerButtonIface->set_property("ButtonPressed", true);
1757 if (!powerButtonMask)
1758 {
1759 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001760 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001761 }
1762 else
1763 {
1764 std::cerr << "power button press masked\n";
1765 }
1766 }
1767 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
1768 {
1769 powerButtonIface->set_property("ButtonPressed", false);
1770 }
1771 powerButtonEvent.async_wait(
1772 boost::asio::posix::stream_descriptor::wait_read,
1773 [](const boost::system::error_code ec) {
1774 if (ec)
1775 {
1776 std::cerr << "power button handler error: " << ec.message()
1777 << "\n";
1778 return;
1779 }
1780 powerButtonHandler();
1781 });
1782}
1783
1784static void resetButtonHandler()
1785{
1786 gpiod::line_event gpioLineEvent = resetButtonLine.event_read();
1787
1788 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1789 {
1790 resetButtonPressLog();
1791 resetButtonIface->set_property("ButtonPressed", true);
1792 if (!resetButtonMask)
1793 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001794 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001795 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001796 }
1797 else
1798 {
1799 std::cerr << "reset button press masked\n";
1800 }
1801 }
1802 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
1803 {
1804 resetButtonIface->set_property("ButtonPressed", false);
1805 }
1806 resetButtonEvent.async_wait(
1807 boost::asio::posix::stream_descriptor::wait_read,
1808 [](const boost::system::error_code ec) {
1809 if (ec)
1810 {
1811 std::cerr << "reset button handler error: " << ec.message()
1812 << "\n";
1813 return;
1814 }
1815 resetButtonHandler();
1816 });
1817}
1818
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07001819static constexpr auto systemdBusname = "org.freedesktop.systemd1";
1820static constexpr auto systemdPath = "/org/freedesktop/systemd1";
1821static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
1822static constexpr auto systemTargetName = "chassis-system-reset.target";
1823
1824void systemReset()
1825{
1826 conn->async_method_call(
1827 [](boost::system::error_code ec) {
1828 if (ec)
1829 {
1830 phosphor::logging::log<phosphor::logging::level::ERR>(
1831 "Failed to call chassis system reset",
1832 phosphor::logging::entry("ERR=%s", ec.message().c_str()));
1833 }
1834 },
1835 systemdBusname, systemdPath, systemdInterface, "StartUnit",
1836 systemTargetName, "replace");
1837}
1838
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001839static void nmiSetEnablePorperty(bool value)
1840{
1841 conn->async_method_call(
1842 [](boost::system::error_code ec) {
1843 if (ec)
1844 {
1845 std::cerr << "failed to set NMI source\n";
1846 }
1847 },
Chen Yugang303bd582019-11-01 08:45:06 +08001848 "xyz.openbmc_project.Settings",
1849 "/xyz/openbmc_project/Chassis/Control/NMISource",
1850 "org.freedesktop.DBus.Properties", "Set",
1851 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
1852 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001853}
1854
1855static void nmiReset(void)
1856{
1857 static constexpr const uint8_t value = 1;
1858 const static constexpr int nmiOutPulseTimeMs = 200;
1859
1860 std::cerr << "NMI out action \n";
1861 nmiOutLine.set_value(value);
1862 std::cerr << nmiOutName << " set to " << std::to_string(value) << "\n";
1863 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
1864 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1865 // restore the NMI_OUT GPIO line back to the opposite value
1866 nmiOutLine.set_value(!value);
1867 std::cerr << nmiOutName << " released\n";
1868 if (ec)
1869 {
1870 // operation_aborted is expected if timer is canceled before
1871 // completion.
1872 if (ec != boost::asio::error::operation_aborted)
1873 {
1874 std::cerr << nmiOutName << " async_wait failed: " + ec.message()
1875 << "\n";
1876 }
1877 }
1878 });
1879 // log to redfish
1880 nmiDiagIntLog();
1881 std::cerr << "NMI out action completed\n";
1882 // reset Enable Property
1883 nmiSetEnablePorperty(false);
1884}
1885
1886static void nmiSourcePropertyMonitor(void)
1887{
1888 std::cerr << " NMI Source Property Monitor \n";
1889
1890 static std::unique_ptr<sdbusplus::bus::match::match> nmiSourceMatch =
1891 std::make_unique<sdbusplus::bus::match::match>(
1892 *conn,
1893 "type='signal',interface='org.freedesktop.DBus.Properties',"
Chen Yugang303bd582019-11-01 08:45:06 +08001894 "member='PropertiesChanged',arg0namespace='xyz.openbmc_project."
1895 "Chassis.Control."
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001896 "NMISource'",
1897 [](sdbusplus::message::message& msg) {
1898 std::string interfaceName;
1899 boost::container::flat_map<std::string,
1900 std::variant<bool, std::string>>
1901 propertiesChanged;
1902 std::string state;
1903 bool value = true;
1904 try
1905 {
1906 msg.read(interfaceName, propertiesChanged);
1907 if (propertiesChanged.begin()->first == "Enabled")
1908 {
1909 value =
1910 std::get<bool>(propertiesChanged.begin()->second);
1911 std::cerr
1912 << " NMI Enabled propertiesChanged value: " << value
1913 << "\n";
1914 nmiEnabled = value;
1915 if (nmiEnabled)
1916 {
1917 nmiReset();
1918 }
1919 }
1920 }
1921 catch (std::exception& e)
1922 {
1923 std::cerr << "Unable to read NMI source\n";
1924 return;
1925 }
1926 });
1927}
1928
1929static void setNmiSource()
1930{
1931 conn->async_method_call(
1932 [](boost::system::error_code ec) {
1933 if (ec)
1934 {
1935 std::cerr << "failed to set NMI source\n";
1936 }
1937 },
Chen Yugang303bd582019-11-01 08:45:06 +08001938 "xyz.openbmc_project.Settings",
1939 "/xyz/openbmc_project/Chassis/Control/NMISource",
1940 "org.freedesktop.DBus.Properties", "Set",
1941 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
1942 std::variant<std::string>{"xyz.openbmc_project.Chassis.Control."
1943 "NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001944 // set Enable Property
1945 nmiSetEnablePorperty(true);
1946}
1947
1948static void nmiButtonHandler()
1949{
1950 gpiod::line_event gpioLineEvent = nmiButtonLine.event_read();
1951
1952 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1953 {
1954 nmiButtonPressLog();
1955 nmiButtonIface->set_property("ButtonPressed", true);
1956 if (nmiButtonMasked)
1957 {
1958 std::cerr << "NMI button press masked\n";
1959 }
1960 else
1961 {
1962 setNmiSource();
1963 }
1964 }
1965 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
1966 {
1967 nmiButtonIface->set_property("ButtonPressed", false);
1968 }
1969 nmiButtonEvent.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1970 [](const boost::system::error_code ec) {
1971 if (ec)
1972 {
1973 std::cerr << "NMI button handler error: "
1974 << ec.message() << "\n";
1975 return;
1976 }
1977 nmiButtonHandler();
1978 });
1979}
1980
1981static void idButtonHandler()
1982{
1983 gpiod::line_event gpioLineEvent = idButtonLine.event_read();
1984
1985 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1986 {
1987 idButtonIface->set_property("ButtonPressed", true);
1988 }
1989 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
1990 {
1991 idButtonIface->set_property("ButtonPressed", false);
1992 }
1993 idButtonEvent.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1994 [](const boost::system::error_code& ec) {
1995 if (ec)
1996 {
1997 std::cerr << "ID button handler error: "
1998 << ec.message() << "\n";
1999 return;
2000 }
2001 idButtonHandler();
2002 });
2003}
2004
2005static void postCompleteHandler()
2006{
2007 gpiod::line_event gpioLineEvent = postCompleteLine.event_read();
2008
2009 bool postComplete =
2010 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002011 if (postComplete)
2012 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002013 sendPowerControlEvent(Event::postCompleteAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002014 osIface->set_property("OperatingSystemState", std::string("Standby"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002015 }
2016 else
2017 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002018 sendPowerControlEvent(Event::postCompleteDeAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002019 osIface->set_property("OperatingSystemState", std::string("Inactive"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002020 }
2021 postCompleteEvent.async_wait(
2022 boost::asio::posix::stream_descriptor::wait_read,
2023 [](const boost::system::error_code ec) {
2024 if (ec)
2025 {
2026 std::cerr << "POST complete handler error: " << ec.message()
2027 << "\n";
2028 return;
2029 }
2030 postCompleteHandler();
2031 });
2032}
2033} // namespace power_control
2034
2035int main(int argc, char* argv[])
2036{
2037 std::cerr << "Start Chassis power control service...\n";
2038 power_control::conn =
2039 std::make_shared<sdbusplus::asio::connection>(power_control::io);
2040
2041 // Request all the dbus names
2042 power_control::conn->request_name("xyz.openbmc_project.State.Host");
2043 power_control::conn->request_name("xyz.openbmc_project.State.Chassis");
2044 power_control::conn->request_name(
2045 "xyz.openbmc_project.State.OperatingSystem");
2046 power_control::conn->request_name("xyz.openbmc_project.Chassis.Buttons");
Chen Yugang174ec662019-08-19 19:58:49 +08002047 power_control::conn->request_name("xyz.openbmc_project.Control.Host.NMI");
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002048 power_control::conn->request_name(
2049 "xyz.openbmc_project.Control.Host.RestartCause");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002050
2051 // Request PS_PWROK GPIO events
2052 if (!power_control::requestGPIOEvents(
2053 "PS_PWROK", power_control::psPowerOKHandler,
2054 power_control::psPowerOKLine, power_control::psPowerOKEvent))
2055 {
2056 return -1;
2057 }
2058
2059 // Request SIO_POWER_GOOD GPIO events
2060 if (!power_control::requestGPIOEvents(
2061 "SIO_POWER_GOOD", power_control::sioPowerGoodHandler,
2062 power_control::sioPowerGoodLine, power_control::sioPowerGoodEvent))
2063 {
2064 return -1;
2065 }
2066
2067 // Request SIO_ONCONTROL GPIO events
2068 if (!power_control::requestGPIOEvents(
2069 "SIO_ONCONTROL", power_control::sioOnControlHandler,
2070 power_control::sioOnControlLine, power_control::sioOnControlEvent))
2071 {
2072 return -1;
2073 }
2074
2075 // Request SIO_S5 GPIO events
2076 if (!power_control::requestGPIOEvents("SIO_S5", power_control::sioS5Handler,
2077 power_control::sioS5Line,
2078 power_control::sioS5Event))
2079 {
2080 return -1;
2081 }
2082
2083 // Request POWER_BUTTON GPIO events
2084 if (!power_control::requestGPIOEvents(
2085 "POWER_BUTTON", power_control::powerButtonHandler,
2086 power_control::powerButtonLine, power_control::powerButtonEvent))
2087 {
2088 return -1;
2089 }
2090
2091 // Request RESET_BUTTON GPIO events
2092 if (!power_control::requestGPIOEvents(
2093 "RESET_BUTTON", power_control::resetButtonHandler,
2094 power_control::resetButtonLine, power_control::resetButtonEvent))
2095 {
2096 return -1;
2097 }
2098
2099 // Request NMI_BUTTON GPIO events
Vijay Khemka33a532d2019-11-14 16:50:35 -08002100 power_control::requestGPIOEvents(
2101 "NMI_BUTTON", power_control::nmiButtonHandler,
2102 power_control::nmiButtonLine, power_control::nmiButtonEvent);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002103
2104 // Request ID_BUTTON GPIO events
Vijay Khemka33a532d2019-11-14 16:50:35 -08002105 power_control::requestGPIOEvents(
2106 "ID_BUTTON", power_control::idButtonHandler,
2107 power_control::idButtonLine, power_control::idButtonEvent);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002108
2109 // Request POST_COMPLETE GPIO events
2110 if (!power_control::requestGPIOEvents(
2111 "POST_COMPLETE", power_control::postCompleteHandler,
2112 power_control::postCompleteLine, power_control::postCompleteEvent))
2113 {
2114 return -1;
2115 }
2116
2117 // initialize NMI_OUT GPIO.
Vijay Khemka33a532d2019-11-14 16:50:35 -08002118 power_control::setGPIOOutput(power_control::nmiOutName, 0,
2119 power_control::nmiOutLine);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002120
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002121 // Initialize POWER_OUT and RESET_OUT GPIO.
2122 gpiod::line line;
2123 if (!power_control::setGPIOOutput(power_control::powerOutName, 1, line))
2124 {
2125 return -1;
2126 }
2127
2128 if (!power_control::setGPIOOutput(power_control::resetOutName, 1, line))
2129 {
2130 return -1;
2131 }
2132
2133 // Release line
2134 line.reset();
2135
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002136 // Initialize the power state
2137 power_control::powerState = power_control::PowerState::off;
2138 // Check power good
2139 if (power_control::psPowerOKLine.get_value() > 0)
2140 {
2141 power_control::powerState = power_control::PowerState::on;
2142 }
2143
2144 // Initialize the power state storage
2145 if (power_control::initializePowerStateStorage() < 0)
2146 {
2147 return -1;
2148 }
2149
2150 // Check if we need to start the Power Restore policy
2151 power_control::powerRestorePolicyCheck();
2152
Vijay Khemka33a532d2019-11-14 16:50:35 -08002153 if (power_control::nmiOutLine)
2154 power_control::nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002155
2156 std::cerr << "Initializing power state. ";
2157 power_control::logStateTransition(power_control::powerState);
2158
2159 // Power Control Service
2160 sdbusplus::asio::object_server hostServer =
2161 sdbusplus::asio::object_server(power_control::conn);
2162
2163 // Power Control Interface
2164 power_control::hostIface = hostServer.add_interface(
2165 "/xyz/openbmc_project/state/host0", "xyz.openbmc_project.State.Host");
2166
2167 power_control::hostIface->register_property(
2168 "RequestedHostTransition",
2169 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2170 [](const std::string& requested, std::string& resp) {
2171 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2172 {
2173 sendPowerControlEvent(
2174 power_control::Event::gracefulPowerOffRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002175 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002176 }
2177 else if (requested ==
2178 "xyz.openbmc_project.State.Host.Transition.On")
2179 {
2180 sendPowerControlEvent(power_control::Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002181 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002182 }
2183 else if (requested ==
2184 "xyz.openbmc_project.State.Host.Transition.Reboot")
2185 {
Jason M. Billse7520ba2020-01-31 11:19:03 -08002186 sendPowerControlEvent(power_control::Event::powerCycleRequest);
2187 addRestartCause(power_control::RestartCause::command);
2188 }
2189 else if (requested == "xyz.openbmc_project.State.Host.Transition."
2190 "GracefulWarmReboot")
2191 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002192 sendPowerControlEvent(
2193 power_control::Event::gracefulPowerCycleRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002194 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002195 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002196 else if (requested == "xyz.openbmc_project.State.Host.Transition."
2197 "ForceWarmReboot")
2198 {
2199 sendPowerControlEvent(power_control::Event::resetRequest);
2200 addRestartCause(power_control::RestartCause::command);
2201 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002202 else
2203 {
2204 std::cerr << "Unrecognized host state transition request.\n";
2205 throw std::invalid_argument("Unrecognized Transition Request");
2206 return 0;
2207 }
2208 resp = requested;
2209 return 1;
2210 });
2211 power_control::hostIface->register_property(
2212 "CurrentHostState",
2213 std::string(power_control::getHostState(power_control::powerState)));
2214
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002215 power_control::hostIface->initialize();
2216
2217 // Chassis Control Service
2218 sdbusplus::asio::object_server chassisServer =
2219 sdbusplus::asio::object_server(power_control::conn);
2220
2221 // Chassis Control Interface
2222 power_control::chassisIface =
2223 chassisServer.add_interface("/xyz/openbmc_project/state/chassis0",
2224 "xyz.openbmc_project.State.Chassis");
2225
2226 power_control::chassisIface->register_property(
2227 "RequestedPowerTransition",
2228 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
2229 [](const std::string& requested, std::string& resp) {
2230 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
2231 {
2232 sendPowerControlEvent(power_control::Event::powerOffRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002233 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002234 }
2235 else if (requested ==
2236 "xyz.openbmc_project.State.Chassis.Transition.On")
2237 {
2238 sendPowerControlEvent(power_control::Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002239 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002240 }
2241 else if (requested ==
2242 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2243 {
2244 sendPowerControlEvent(power_control::Event::powerCycleRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002245 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002246 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002247 else
2248 {
2249 std::cerr << "Unrecognized chassis state transition request.\n";
2250 throw std::invalid_argument("Unrecognized Transition Request");
2251 return 0;
2252 }
2253 resp = requested;
2254 return 1;
2255 });
2256 power_control::chassisIface->register_property(
2257 "CurrentPowerState",
2258 std::string(power_control::getChassisState(power_control::powerState)));
2259 power_control::chassisIface->register_property(
2260 "LastStateChangeTime", power_control::getCurrentTimeMs());
2261
2262 power_control::chassisIface->initialize();
2263
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002264 // Chassis System Service
2265 sdbusplus::asio::object_server chassisSysServer =
2266 sdbusplus::asio::object_server(power_control::conn);
2267
2268 // Chassis System Interface
2269 power_control::chassisSysIface = chassisSysServer.add_interface(
2270 "/xyz/openbmc_project/state/chassis_system0",
2271 "xyz.openbmc_project.State.Chassis");
2272
2273 power_control::chassisSysIface->register_property(
2274 "RequestedPowerTransition",
2275 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
2276 [](const std::string& requested, std::string& resp) {
2277 if (requested ==
2278 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2279 {
2280 power_control::systemReset();
2281 addRestartCause(power_control::RestartCause::command);
2282 }
2283 else
2284 {
2285 std::cerr << "Unrecognized chassis system state transition "
2286 "request.\n";
2287 throw std::invalid_argument("Unrecognized Transition Request");
2288 return 0;
2289 }
2290 resp = requested;
2291 return 1;
2292 });
2293 power_control::chassisSysIface->register_property(
2294 "CurrentPowerState",
2295 std::string(power_control::getChassisState(power_control::powerState)));
2296 power_control::chassisSysIface->register_property(
2297 "LastStateChangeTime", power_control::getCurrentTimeMs());
2298
2299 power_control::chassisSysIface->initialize();
2300
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002301 // Buttons Service
2302 sdbusplus::asio::object_server buttonsServer =
2303 sdbusplus::asio::object_server(power_control::conn);
2304
2305 // Power Button Interface
2306 power_control::powerButtonIface = buttonsServer.add_interface(
2307 "/xyz/openbmc_project/chassis/buttons/power",
2308 "xyz.openbmc_project.Chassis.Buttons");
2309
2310 power_control::powerButtonIface->register_property(
2311 "ButtonMasked", false, [](const bool requested, bool& current) {
2312 if (requested)
2313 {
2314 if (power_control::powerButtonMask)
2315 {
2316 return 1;
2317 }
2318 if (!power_control::setGPIOOutput(
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002319 power_control::powerOutName, 1,
2320 power_control::powerButtonMask))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002321 {
2322 throw std::runtime_error("Failed to request GPIO");
2323 return 0;
2324 }
2325 std::cerr << "Power Button Masked.\n";
2326 }
2327 else
2328 {
2329 if (!power_control::powerButtonMask)
2330 {
2331 return 1;
2332 }
2333 std::cerr << "Power Button Un-masked\n";
2334 power_control::powerButtonMask.reset();
2335 }
2336 // Update the mask setting
2337 current = requested;
2338 return 1;
2339 });
2340
2341 // Check power button state
2342 bool powerButtonPressed = power_control::powerButtonLine.get_value() == 0;
2343 power_control::powerButtonIface->register_property("ButtonPressed",
2344 powerButtonPressed);
2345
2346 power_control::powerButtonIface->initialize();
2347
2348 // Reset Button Interface
2349 power_control::resetButtonIface = buttonsServer.add_interface(
2350 "/xyz/openbmc_project/chassis/buttons/reset",
2351 "xyz.openbmc_project.Chassis.Buttons");
2352
2353 power_control::resetButtonIface->register_property(
2354 "ButtonMasked", false, [](const bool requested, bool& current) {
2355 if (requested)
2356 {
2357 if (power_control::resetButtonMask)
2358 {
2359 return 1;
2360 }
2361 if (!power_control::setGPIOOutput(
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002362 power_control::resetOutName, 1,
2363 power_control::resetButtonMask))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002364 {
2365 throw std::runtime_error("Failed to request GPIO");
2366 return 0;
2367 }
2368 std::cerr << "Reset Button Masked.\n";
2369 }
2370 else
2371 {
2372 if (!power_control::resetButtonMask)
2373 {
2374 return 1;
2375 }
2376 std::cerr << "Reset Button Un-masked\n";
2377 power_control::resetButtonMask.reset();
2378 }
2379 // Update the mask setting
2380 current = requested;
2381 return 1;
2382 });
2383
2384 // Check reset button state
2385 bool resetButtonPressed = power_control::resetButtonLine.get_value() == 0;
2386 power_control::resetButtonIface->register_property("ButtonPressed",
2387 resetButtonPressed);
2388
2389 power_control::resetButtonIface->initialize();
2390
Vijay Khemka33a532d2019-11-14 16:50:35 -08002391 if (power_control::nmiButtonLine)
2392 {
2393 // NMI Button Interface
2394 power_control::nmiButtonIface = buttonsServer.add_interface(
2395 "/xyz/openbmc_project/chassis/buttons/nmi",
2396 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002397
Vijay Khemka33a532d2019-11-14 16:50:35 -08002398 power_control::nmiButtonIface->register_property(
2399 "ButtonMasked", false, [](const bool requested, bool& current) {
2400 if (power_control::nmiButtonMasked == requested)
2401 {
2402 // NMI button mask is already set as requested, so no change
2403 return 1;
2404 }
2405 if (requested)
2406 {
2407 std::cerr << "NMI Button Masked.\n";
2408 power_control::nmiButtonMasked = true;
2409 }
2410 else
2411 {
2412 std::cerr << "NMI Button Un-masked.\n";
2413 power_control::nmiButtonMasked = false;
2414 }
2415 // Update the mask setting
2416 current = power_control::nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002417 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08002418 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002419
Vijay Khemka33a532d2019-11-14 16:50:35 -08002420 // Check NMI button state
2421 bool nmiButtonPressed = power_control::nmiButtonLine.get_value() == 0;
2422 power_control::nmiButtonIface->register_property("ButtonPressed",
2423 nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002424
Vijay Khemka33a532d2019-11-14 16:50:35 -08002425 power_control::nmiButtonIface->initialize();
2426 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002427
Vijay Khemka33a532d2019-11-14 16:50:35 -08002428 if (power_control::nmiOutLine)
2429 {
2430 // NMI out Service
2431 sdbusplus::asio::object_server nmiOutServer =
2432 sdbusplus::asio::object_server(power_control::conn);
Chen Yugang174ec662019-08-19 19:58:49 +08002433
Vijay Khemka33a532d2019-11-14 16:50:35 -08002434 // NMI out Interface
2435 power_control::nmiOutIface =
2436 nmiOutServer.add_interface("/xyz/openbmc_project/control/host0/nmi",
2437 "xyz.openbmc_project.Control.Host.NMI");
2438 power_control::nmiOutIface->register_method("NMI",
2439 power_control::nmiReset);
2440 power_control::nmiOutIface->initialize();
2441 }
Chen Yugang174ec662019-08-19 19:58:49 +08002442
Vijay Khemka33a532d2019-11-14 16:50:35 -08002443 if (power_control::idButtonLine)
2444 {
2445 // ID Button Interface
2446 power_control::idButtonIface = buttonsServer.add_interface(
2447 "/xyz/openbmc_project/chassis/buttons/id",
2448 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002449
Vijay Khemka33a532d2019-11-14 16:50:35 -08002450 // Check ID button state
2451 bool idButtonPressed = power_control::idButtonLine.get_value() == 0;
2452 power_control::idButtonIface->register_property("ButtonPressed",
2453 idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002454
Vijay Khemka33a532d2019-11-14 16:50:35 -08002455 power_control::idButtonIface->initialize();
2456 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002457
2458 // OS State Service
2459 sdbusplus::asio::object_server osServer =
2460 sdbusplus::asio::object_server(power_control::conn);
2461
2462 // OS State Interface
2463 power_control::osIface = osServer.add_interface(
2464 "/xyz/openbmc_project/state/os",
2465 "xyz.openbmc_project.State.OperatingSystem.Status");
2466
2467 // Get the initial OS state based on POST complete
2468 // 0: Asserted, OS state is "Standby" (ready to boot)
2469 // 1: De-Asserted, OS state is "Inactive"
2470 std::string osState = power_control::postCompleteLine.get_value() > 0
2471 ? "Inactive"
2472 : "Standby";
2473
2474 power_control::osIface->register_property("OperatingSystemState",
2475 std::string(osState));
2476
2477 power_control::osIface->initialize();
2478
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002479 // Restart Cause Service
2480 sdbusplus::asio::object_server restartCauseServer =
2481 sdbusplus::asio::object_server(power_control::conn);
2482
2483 // Restart Cause Interface
2484 power_control::restartCauseIface = restartCauseServer.add_interface(
2485 "/xyz/openbmc_project/control/host0/restart_cause",
2486 "xyz.openbmc_project.Control.Host.RestartCause");
2487
2488 power_control::restartCauseIface->register_property(
2489 "RestartCause",
2490 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
2491
2492 power_control::restartCauseIface->register_property(
2493 "RequestedRestartCause",
2494 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
2495 [](const std::string& requested, std::string& resp) {
2496 if (requested ==
2497 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
2498 {
2499 power_control::addRestartCause(
2500 power_control::RestartCause::watchdog);
2501 }
2502 else
2503 {
2504 throw std::invalid_argument(
2505 "Unrecognized RestartCause Request");
2506 return 0;
2507 }
2508
2509 std::cerr << "RestartCause requested: " << requested << "\n";
2510 resp = requested;
2511 return 1;
2512 });
2513
2514 power_control::restartCauseIface->initialize();
2515
Yong Li8d660212019-12-27 10:18:10 +08002516 power_control::currentHostStateMonitor();
2517
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002518 power_control::io.run();
2519
2520 return 0;
2521}