blob: 3ba16ddc7860d84be748dbbe374a9fe7eae644b1 [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,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700137 off,
138 transitionToOff,
139 gracefulTransitionToOff,
140 cycleOff,
141 transitionToCycleOff,
142 gracefulTransitionToCycleOff,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700143 checkForWarmReset,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700144};
145static PowerState powerState;
146static std::string getPowerStateName(PowerState state)
147{
148 switch (state)
149 {
150 case PowerState::on:
151 return "On";
152 break;
153 case PowerState::waitForPSPowerOK:
154 return "Wait for Power Supply Power OK";
155 break;
156 case PowerState::waitForSIOPowerGood:
157 return "Wait for SIO Power Good";
158 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700159 case PowerState::off:
160 return "Off";
161 break;
162 case PowerState::transitionToOff:
163 return "Transition to Off";
164 break;
165 case PowerState::gracefulTransitionToOff:
166 return "Graceful Transition to Off";
167 break;
168 case PowerState::cycleOff:
169 return "Power Cycle Off";
170 break;
171 case PowerState::transitionToCycleOff:
172 return "Transition to Power Cycle Off";
173 break;
174 case PowerState::gracefulTransitionToCycleOff:
175 return "Graceful Transition to Power Cycle Off";
176 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700177 case PowerState::checkForWarmReset:
178 return "Check for Warm Reset";
179 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700180 default:
181 return "unknown state: " + std::to_string(static_cast<int>(state));
182 break;
183 }
184}
185static void logStateTransition(const PowerState state)
186{
Vijay Khemkad6c5ad12020-05-27 14:57:52 -0700187 std::string logMsg =
188 "Host0: Moving to \"" + getPowerStateName(state) + "\" state";
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700189 phosphor::logging::log<phosphor::logging::level::INFO>(
190 logMsg.c_str(),
Vijay Khemkad6c5ad12020-05-27 14:57:52 -0700191 phosphor::logging::entry("STATE=%s", getPowerStateName(state).c_str()),
192 phosphor::logging::entry("HOST=0"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700193}
194
195enum class Event
196{
197 psPowerOKAssert,
198 psPowerOKDeAssert,
199 sioPowerGoodAssert,
200 sioPowerGoodDeAssert,
201 sioS5Assert,
202 sioS5DeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700203 postCompleteAssert,
204 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700205 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700206 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700207 powerCycleTimerExpired,
208 psPowerOKWatchdogTimerExpired,
209 sioPowerGoodWatchdogTimerExpired,
210 gracefulPowerOffTimerExpired,
211 powerOnRequest,
212 powerOffRequest,
213 powerCycleRequest,
214 resetRequest,
215 gracefulPowerOffRequest,
216 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700217 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700218};
219static std::string getEventName(Event event)
220{
221 switch (event)
222 {
223 case Event::psPowerOKAssert:
224 return "power supply power OK assert";
225 break;
226 case Event::psPowerOKDeAssert:
227 return "power supply power OK de-assert";
228 break;
229 case Event::sioPowerGoodAssert:
230 return "SIO power good assert";
231 break;
232 case Event::sioPowerGoodDeAssert:
233 return "SIO power good de-assert";
234 break;
235 case Event::sioS5Assert:
236 return "SIO S5 assert";
237 break;
238 case Event::sioS5DeAssert:
239 return "SIO S5 de-assert";
240 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700241 case Event::postCompleteAssert:
242 return "POST Complete assert";
243 break;
244 case Event::postCompleteDeAssert:
245 return "POST Complete de-assert";
246 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700247 case Event::powerButtonPressed:
248 return "power button pressed";
249 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700250 case Event::resetButtonPressed:
251 return "reset button pressed";
252 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700253 case Event::powerCycleTimerExpired:
254 return "power cycle timer expired";
255 break;
256 case Event::psPowerOKWatchdogTimerExpired:
257 return "power supply power OK watchdog timer expired";
258 break;
259 case Event::sioPowerGoodWatchdogTimerExpired:
260 return "SIO power good watchdog timer expired";
261 break;
262 case Event::gracefulPowerOffTimerExpired:
263 return "graceful power-off timer expired";
264 break;
265 case Event::powerOnRequest:
266 return "power-on request";
267 break;
268 case Event::powerOffRequest:
269 return "power-off request";
270 break;
271 case Event::powerCycleRequest:
272 return "power-cycle request";
273 break;
274 case Event::resetRequest:
275 return "reset request";
276 break;
277 case Event::gracefulPowerOffRequest:
278 return "graceful power-off request";
279 break;
280 case Event::gracefulPowerCycleRequest:
281 return "graceful power-cycle request";
282 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700283 case Event::warmResetDetected:
284 return "warm reset detected";
285 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700286 default:
287 return "unknown event: " + std::to_string(static_cast<int>(event));
288 break;
289 }
290}
291static void logEvent(const std::string_view stateHandler, const Event event)
292{
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700293 std::string logMsg{stateHandler};
294 logMsg += ": " + getEventName(event) + " event received";
295 phosphor::logging::log<phosphor::logging::level::INFO>(
296 logMsg.c_str(),
297 phosphor::logging::entry("EVENT=%s", getEventName(event).c_str()));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700298}
299
300// Power state handlers
301static void powerStateOn(const Event event);
302static void powerStateWaitForPSPowerOK(const Event event);
303static void powerStateWaitForSIOPowerGood(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700304static void powerStateOff(const Event event);
305static void powerStateTransitionToOff(const Event event);
306static void powerStateGracefulTransitionToOff(const Event event);
307static void powerStateCycleOff(const Event event);
308static void powerStateTransitionToCycleOff(const Event event);
309static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700310static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700311
312static std::function<void(const Event)> getPowerStateHandler(PowerState state)
313{
314 switch (state)
315 {
316 case PowerState::on:
317 return powerStateOn;
318 break;
319 case PowerState::waitForPSPowerOK:
320 return powerStateWaitForPSPowerOK;
321 break;
322 case PowerState::waitForSIOPowerGood:
323 return powerStateWaitForSIOPowerGood;
324 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700325 case PowerState::off:
326 return powerStateOff;
327 break;
328 case PowerState::transitionToOff:
329 return powerStateTransitionToOff;
330 break;
331 case PowerState::gracefulTransitionToOff:
332 return powerStateGracefulTransitionToOff;
333 break;
334 case PowerState::cycleOff:
335 return powerStateCycleOff;
336 break;
337 case PowerState::transitionToCycleOff:
338 return powerStateTransitionToCycleOff;
339 break;
340 case PowerState::gracefulTransitionToCycleOff:
341 return powerStateGracefulTransitionToCycleOff;
342 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700343 case PowerState::checkForWarmReset:
344 return powerStateCheckForWarmReset;
345 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700346 default:
347 return std::function<void(const Event)>{};
348 break;
349 }
350};
351
352static void sendPowerControlEvent(const Event event)
353{
354 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
355 if (handler == nullptr)
356 {
357 std::cerr << "Failed to find handler for power state: "
358 << static_cast<int>(powerState) << "\n";
359 return;
360 }
361 handler(event);
362}
363
364static uint64_t getCurrentTimeMs()
365{
366 struct timespec time = {};
367
368 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
369 {
370 return 0;
371 }
372 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
373 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
374
375 return currentTimeMs;
376}
377
378static constexpr std::string_view getHostState(const PowerState state)
379{
380 switch (state)
381 {
382 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700383 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700384 case PowerState::gracefulTransitionToCycleOff:
385 return "xyz.openbmc_project.State.Host.HostState.Running";
386 break;
387 case PowerState::waitForPSPowerOK:
388 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700389 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700390 case PowerState::transitionToOff:
391 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700392 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700393 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700394 return "xyz.openbmc_project.State.Host.HostState.Off";
395 break;
396 default:
397 return "";
398 break;
399 }
400};
401static constexpr std::string_view getChassisState(const PowerState state)
402{
403 switch (state)
404 {
405 case PowerState::on:
406 case PowerState::transitionToOff:
407 case PowerState::gracefulTransitionToOff:
408 case PowerState::transitionToCycleOff:
409 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700410 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700411 return "xyz.openbmc_project.State.Chassis.PowerState.On";
412 break;
413 case PowerState::waitForPSPowerOK:
414 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700415 case PowerState::off:
416 case PowerState::cycleOff:
417 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
418 break;
419 default:
420 return "";
421 break;
422 }
423};
424static void savePowerState(const PowerState state)
425{
426 powerStateSaveTimer.expires_after(
427 std::chrono::milliseconds(powerOffSaveTimeMs));
428 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
429 if (ec)
430 {
431 // operation_aborted is expected if timer is canceled before
432 // completion.
433 if (ec != boost::asio::error::operation_aborted)
434 {
435 std::cerr << "Power-state save async_wait failed: "
436 << ec.message() << "\n";
437 }
438 return;
439 }
440 std::ofstream powerStateStream(powerControlDir / powerStateFile);
441 powerStateStream << getChassisState(state);
442 });
443}
444static void setPowerState(const PowerState state)
445{
446 powerState = state;
447 logStateTransition(state);
448
449 hostIface->set_property("CurrentHostState",
450 std::string(getHostState(powerState)));
451
452 chassisIface->set_property("CurrentPowerState",
453 std::string(getChassisState(powerState)));
454 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
455
456 // Save the power state for the restore policy
457 savePowerState(state);
458}
459
460enum class RestartCause
461{
462 command,
463 resetButton,
464 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700465 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700466 powerPolicyOn,
467 powerPolicyRestore,
468 softReset,
469};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700470static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700471static std::string getRestartCause(RestartCause cause)
472{
473 switch (cause)
474 {
475 case RestartCause::command:
476 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
477 break;
478 case RestartCause::resetButton:
479 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
480 break;
481 case RestartCause::powerButton:
482 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
483 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700484 case RestartCause::watchdog:
485 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
486 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700487 case RestartCause::powerPolicyOn:
488 return "xyz.openbmc_project.State.Host.RestartCause."
489 "PowerPolicyAlwaysOn";
490 break;
491 case RestartCause::powerPolicyRestore:
492 return "xyz.openbmc_project.State.Host.RestartCause."
493 "PowerPolicyPreviousState";
494 break;
495 case RestartCause::softReset:
496 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
497 break;
498 default:
499 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
500 break;
501 }
502}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700503static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700504{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700505 // Add this to the set of causes for this restart
506 causeSet.insert(cause);
507}
508static void clearRestartCause()
509{
510 // Clear the set for the next restart
511 causeSet.clear();
512}
513static void setRestartCauseProperty(const std::string& cause)
514{
515 std::cerr << "RestartCause set to " << cause << "\n";
516 restartCauseIface->set_property("RestartCause", cause);
517}
Rashmi RV89f61312020-01-22 15:41:50 +0530518
519static void resetACBootProperty()
520{
521 if ((causeSet.contains(RestartCause::command)) ||
522 (causeSet.contains(RestartCause::softReset)))
523 {
524 conn->async_method_call(
525 [](boost::system::error_code ec) {
526 if (ec)
527 {
528 std::cerr << "failed to reset ACBoot property\n";
529 }
530 },
531 "xyz.openbmc_project.Settings",
532 "/xyz/openbmc_project/control/host0/ac_boot",
533 "org.freedesktop.DBus.Properties", "Set",
534 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
535 std::variant<std::string>{"False"});
536 }
537}
538
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700539static void setRestartCause()
540{
541 // Determine the actual restart cause based on the set of causes
542 std::string restartCause =
543 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
544 if (causeSet.contains(RestartCause::watchdog))
545 {
546 restartCause = getRestartCause(RestartCause::watchdog);
547 }
548 else if (causeSet.contains(RestartCause::command))
549 {
550 restartCause = getRestartCause(RestartCause::command);
551 }
552 else if (causeSet.contains(RestartCause::resetButton))
553 {
554 restartCause = getRestartCause(RestartCause::resetButton);
555 }
556 else if (causeSet.contains(RestartCause::powerButton))
557 {
558 restartCause = getRestartCause(RestartCause::powerButton);
559 }
560 else if (causeSet.contains(RestartCause::powerPolicyOn))
561 {
562 restartCause = getRestartCause(RestartCause::powerPolicyOn);
563 }
564 else if (causeSet.contains(RestartCause::powerPolicyRestore))
565 {
566 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
567 }
568 else if (causeSet.contains(RestartCause::softReset))
569 {
570 restartCause = getRestartCause(RestartCause::softReset);
571 }
572
573 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700574}
575
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700576static void systemPowerGoodFailedLog()
577{
578 sd_journal_send(
579 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
580 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
581 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
582 sioPowerGoodWatchdogTimeMs, NULL);
583}
584
585static void psPowerOKFailedLog()
586{
587 sd_journal_send(
588 "MESSAGE=PowerControl: power supply power good failed to assert",
589 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
590 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
591 psPowerOKWatchdogTimeMs, NULL);
592}
593
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700594static void powerRestorePolicyLog()
595{
596 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
597 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
598 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
599}
600
601static void powerButtonPressLog()
602{
603 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
604 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
605 "OpenBMC.0.1.PowerButtonPressed", NULL);
606}
607
608static void resetButtonPressLog()
609{
610 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
611 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
612 "OpenBMC.0.1.ResetButtonPressed", NULL);
613}
614
615static void nmiButtonPressLog()
616{
617 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
618 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
619 "OpenBMC.0.1.NMIButtonPressed", NULL);
620}
621
622static void nmiDiagIntLog()
623{
624 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
625 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
626 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
627}
628
629static int initializePowerStateStorage()
630{
631 // create the power control directory if it doesn't exist
632 std::error_code ec;
633 if (!(std::filesystem::create_directories(powerControlDir, ec)))
634 {
635 if (ec.value() != 0)
636 {
637 std::cerr << "failed to create " << powerControlDir << ": "
638 << ec.message() << "\n";
639 return -1;
640 }
641 }
642 // Create the power state file if it doesn't exist
643 if (!std::filesystem::exists(powerControlDir / powerStateFile))
644 {
645 std::ofstream powerStateStream(powerControlDir / powerStateFile);
646 powerStateStream << getChassisState(powerState);
647 }
648 return 0;
649}
650
651static bool wasPowerDropped()
652{
653 std::ifstream powerStateStream(powerControlDir / powerStateFile);
654 if (!powerStateStream.is_open())
655 {
656 std::cerr << "Failed to open power state file\n";
657 return false;
658 }
659
660 std::string state;
661 std::getline(powerStateStream, state);
662 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
663}
664
665static void invokePowerRestorePolicy(const std::string& policy)
666{
667 // Async events may call this twice, but we only want to run once
668 static bool policyInvoked = false;
669 if (policyInvoked)
670 {
671 return;
672 }
673 policyInvoked = true;
674
675 std::cerr << "Power restore delay expired, invoking " << policy << "\n";
676 if (policy ==
677 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
678 {
679 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700680 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700681 }
682 else if (policy == "xyz.openbmc_project.Control.Power.RestorePolicy."
683 "Policy.Restore")
684 {
685 if (wasPowerDropped())
686 {
687 std::cerr << "Power was dropped, restoring Host On state\n";
688 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700689 setRestartCauseProperty(
690 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700691 }
692 else
693 {
694 std::cerr << "No power drop, restoring Host Off state\n";
695 }
696 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -0700697 // We're done with the previous power state for the restore policy, so store
698 // the current state
699 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700700}
701
702static void powerRestorePolicyDelay(int delay)
703{
704 // Async events may call this twice, but we only want to run once
705 static bool delayStarted = false;
706 if (delayStarted)
707 {
708 return;
709 }
710 delayStarted = true;
711 // Calculate the delay from now to meet the requested delay
712 // Subtract the approximate uboot time
713 static constexpr const int ubootSeconds = 20;
714 delay -= ubootSeconds;
715 // Subtract the time since boot
716 struct sysinfo info = {};
717 if (sysinfo(&info) == 0)
718 {
719 delay -= info.uptime;
720 }
721 // 0 is the minimum delay
722 delay = std::max(delay, 0);
723
724 static boost::asio::steady_timer powerRestorePolicyTimer(io);
725 powerRestorePolicyTimer.expires_after(std::chrono::seconds(delay));
726 std::cerr << "Power restore delay of " << delay << " seconds started\n";
727 powerRestorePolicyTimer.async_wait([](const boost::system::error_code ec) {
728 if (ec)
729 {
730 // operation_aborted is expected if timer is canceled before
731 // completion.
732 if (ec != boost::asio::error::operation_aborted)
733 {
734 std::cerr << "power restore policy async_wait failed: "
735 << ec.message() << "\n";
736 }
737 return;
738 }
739 // Get Power Restore Policy
740 // In case PowerRestorePolicy is not available, set a match for it
741 static std::unique_ptr<sdbusplus::bus::match::match>
742 powerRestorePolicyMatch = std::make_unique<
743 sdbusplus::bus::match::match>(
744 *conn,
745 "type='signal',interface='org.freedesktop.DBus.Properties',"
746 "member='PropertiesChanged',arg0namespace='xyz.openbmc_"
747 "project.Control.Power.RestorePolicy'",
748 [](sdbusplus::message::message& msg) {
749 std::string interfaceName;
750 boost::container::flat_map<std::string,
751 std::variant<std::string>>
752 propertiesChanged;
753 std::string policy;
754 try
755 {
756 msg.read(interfaceName, propertiesChanged);
757 policy = std::get<std::string>(
758 propertiesChanged.begin()->second);
759 }
760 catch (std::exception& e)
761 {
762 std::cerr
763 << "Unable to read power restore policy value\n";
764 powerRestorePolicyMatch.reset();
765 return;
766 }
767 invokePowerRestorePolicy(policy);
768 powerRestorePolicyMatch.reset();
769 });
770
771 // Check if it's already on DBus
772 conn->async_method_call(
773 [](boost::system::error_code ec,
774 const std::variant<std::string>& policyProperty) {
775 if (ec)
776 {
777 return;
778 }
779 powerRestorePolicyMatch.reset();
780 const std::string* policy =
781 std::get_if<std::string>(&policyProperty);
782 if (policy == nullptr)
783 {
784 std::cerr << "Unable to read power restore policy value\n";
785 return;
786 }
787 invokePowerRestorePolicy(*policy);
788 },
789 "xyz.openbmc_project.Settings",
790 "/xyz/openbmc_project/control/host0/power_restore_policy",
791 "org.freedesktop.DBus.Properties", "Get",
792 "xyz.openbmc_project.Control.Power.RestorePolicy",
793 "PowerRestorePolicy");
794 });
795}
796
797static void powerRestorePolicyStart()
798{
799 std::cerr << "Power restore policy started\n";
800 powerRestorePolicyLog();
801
802 // Get the desired delay time
803 // In case PowerRestoreDelay is not available, set a match for it
804 static std::unique_ptr<sdbusplus::bus::match::match>
805 powerRestoreDelayMatch = std::make_unique<sdbusplus::bus::match::match>(
806 *conn,
807 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
808 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Control."
809 "Power.RestoreDelay'",
810 [](sdbusplus::message::message& msg) {
811 std::string interfaceName;
812 boost::container::flat_map<std::string, std::variant<uint16_t>>
813 propertiesChanged;
814 int delay = 0;
815 try
816 {
817 msg.read(interfaceName, propertiesChanged);
818 delay =
819 std::get<uint16_t>(propertiesChanged.begin()->second);
820 }
821 catch (std::exception& e)
822 {
823 std::cerr << "Unable to read power restore delay value\n";
824 powerRestoreDelayMatch.reset();
825 return;
826 }
827 powerRestorePolicyDelay(delay);
828 powerRestoreDelayMatch.reset();
829 });
830
831 // Check if it's already on DBus
832 conn->async_method_call(
833 [](boost::system::error_code ec,
834 const std::variant<uint16_t>& delayProperty) {
835 if (ec)
836 {
837 return;
838 }
839 powerRestoreDelayMatch.reset();
840 const uint16_t* delay = std::get_if<uint16_t>(&delayProperty);
841 if (delay == nullptr)
842 {
843 std::cerr << "Unable to read power restore delay value\n";
844 return;
845 }
846 powerRestorePolicyDelay(*delay);
847 },
848 "xyz.openbmc_project.Settings",
849 "/xyz/openbmc_project/control/power_restore_delay",
850 "org.freedesktop.DBus.Properties", "Get",
851 "xyz.openbmc_project.Control.Power.RestoreDelay", "PowerRestoreDelay");
852}
853
854static void powerRestorePolicyCheck()
855{
856 // In case ACBoot is not available, set a match for it
857 static std::unique_ptr<sdbusplus::bus::match::match> acBootMatch =
858 std::make_unique<sdbusplus::bus::match::match>(
859 *conn,
860 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
861 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Common."
862 "ACBoot'",
863 [](sdbusplus::message::message& msg) {
864 std::string interfaceName;
865 boost::container::flat_map<std::string,
866 std::variant<std::string>>
867 propertiesChanged;
868 std::string acBoot;
869 try
870 {
871 msg.read(interfaceName, propertiesChanged);
872 acBoot = std::get<std::string>(
873 propertiesChanged.begin()->second);
874 }
875 catch (std::exception& e)
876 {
877 std::cerr << "Unable to read AC Boot status\n";
878 acBootMatch.reset();
879 return;
880 }
881 if (acBoot == "Unknown")
882 {
883 return;
884 }
885 if (acBoot == "True")
886 {
887 // Start the Power Restore policy
888 powerRestorePolicyStart();
889 }
890 acBootMatch.reset();
891 });
892
893 // Check if it's already on DBus
894 conn->async_method_call(
895 [](boost::system::error_code ec,
896 const std::variant<std::string>& acBootProperty) {
897 if (ec)
898 {
899 return;
900 }
901 const std::string* acBoot =
902 std::get_if<std::string>(&acBootProperty);
903 if (acBoot == nullptr)
904 {
905 std::cerr << "Unable to read AC Boot status\n";
906 return;
907 }
908 if (*acBoot == "Unknown")
909 {
910 return;
911 }
912 if (*acBoot == "True")
913 {
914 // Start the Power Restore policy
915 powerRestorePolicyStart();
916 }
917 acBootMatch.reset();
918 },
919 "xyz.openbmc_project.Settings",
920 "/xyz/openbmc_project/control/host0/ac_boot",
921 "org.freedesktop.DBus.Properties", "Get",
922 "xyz.openbmc_project.Common.ACBoot", "ACBoot");
923}
924
925static bool requestGPIOEvents(
926 const std::string& name, const std::function<void()>& handler,
927 gpiod::line& gpioLine,
928 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
929{
930 // Find the GPIO line
931 gpioLine = gpiod::find_line(name);
932 if (!gpioLine)
933 {
934 std::cerr << "Failed to find the " << name << " line\n";
935 return false;
936 }
937
938 try
939 {
940 gpioLine.request(
941 {"power-control", gpiod::line_request::EVENT_BOTH_EDGES});
942 }
943 catch (std::exception&)
944 {
945 std::cerr << "Failed to request events for " << name << "\n";
946 return false;
947 }
948
949 int gpioLineFd = gpioLine.event_get_fd();
950 if (gpioLineFd < 0)
951 {
952 std::cerr << "Failed to get " << name << " fd\n";
953 return false;
954 }
955
956 gpioEventDescriptor.assign(gpioLineFd);
957
958 gpioEventDescriptor.async_wait(
959 boost::asio::posix::stream_descriptor::wait_read,
960 [&name, handler](const boost::system::error_code ec) {
961 if (ec)
962 {
963 std::cerr << name << " fd handler error: " << ec.message()
964 << "\n";
965 // TODO: throw here to force power-control to restart?
966 return;
967 }
968 handler();
969 });
970 return true;
971}
972
973static bool setGPIOOutput(const std::string& name, const int value,
974 gpiod::line& gpioLine)
975{
976 // Find the GPIO line
977 gpioLine = gpiod::find_line(name);
978 if (!gpioLine)
979 {
980 std::cerr << "Failed to find the " << name << " line.\n";
981 return false;
982 }
983
984 // Request GPIO output to specified value
985 try
986 {
987 gpioLine.request({__FUNCTION__, gpiod::line_request::DIRECTION_OUTPUT},
988 value);
989 }
990 catch (std::exception&)
991 {
992 std::cerr << "Failed to request " << name << " output\n";
993 return false;
994 }
995
996 std::cerr << name << " set to " << std::to_string(value) << "\n";
997 return true;
998}
999
1000static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1001 const std::string& name, const int value,
1002 const int durationMs)
1003{
1004 // Set the masked GPIO line to the specified value
1005 maskedGPIOLine.set_value(value);
1006 std::cerr << name << " set to " << std::to_string(value) << "\n";
1007 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
1008 gpioAssertTimer.async_wait(
1009 [maskedGPIOLine, value, name](const boost::system::error_code ec) {
1010 // Set the masked GPIO line back to the opposite value
1011 maskedGPIOLine.set_value(!value);
1012 std::cerr << name << " released\n";
1013 if (ec)
1014 {
1015 // operation_aborted is expected if timer is canceled before
1016 // completion.
1017 if (ec != boost::asio::error::operation_aborted)
1018 {
1019 std::cerr << name << " async_wait failed: " + ec.message()
1020 << "\n";
1021 }
1022 }
1023 });
1024 return 0;
1025}
1026
1027static int setGPIOOutputForMs(const std::string& name, const int value,
1028 const int durationMs)
1029{
1030 // If the requested GPIO is masked, use the mask line to set the output
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001031 if (powerButtonMask && name == power_control::powerOutName)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001032 {
1033 return setMaskedGPIOOutputForMs(powerButtonMask, name, value,
1034 durationMs);
1035 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001036 if (resetButtonMask && name == power_control::resetOutName)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001037 {
1038 return setMaskedGPIOOutputForMs(resetButtonMask, name, value,
1039 durationMs);
1040 }
1041
1042 // No mask set, so request and set the GPIO normally
1043 gpiod::line gpioLine;
1044 if (!setGPIOOutput(name, value, gpioLine))
1045 {
1046 return -1;
1047 }
1048 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
1049 gpioAssertTimer.async_wait(
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001050 [gpioLine, value, name](const boost::system::error_code ec) {
1051 // Set the GPIO line back to the opposite value
1052 gpioLine.set_value(!value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001053 std::cerr << name << " released\n";
1054 if (ec)
1055 {
1056 // operation_aborted is expected if timer is canceled before
1057 // completion.
1058 if (ec != boost::asio::error::operation_aborted)
1059 {
1060 std::cerr << name << " async_wait failed: " << ec.message()
1061 << "\n";
1062 }
1063 }
1064 });
1065 return 0;
1066}
1067
1068static void powerOn()
1069{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001070 setGPIOOutputForMs(power_control::powerOutName, 0, powerPulseTimeMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001071}
1072
1073static void gracefulPowerOff()
1074{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001075 setGPIOOutputForMs(power_control::powerOutName, 0, powerPulseTimeMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001076}
1077
1078static void forcePowerOff()
1079{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001080 if (setGPIOOutputForMs(power_control::powerOutName, 0,
1081 forceOffPulseTimeMs) < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001082 {
1083 return;
1084 }
1085
1086 // If the force off timer expires, then the PCH power-button override
1087 // failed, so attempt the Unconditional Powerdown SMBus command.
1088 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1089 if (ec)
1090 {
1091 // operation_aborted is expected if timer is canceled before
1092 // completion.
1093 if (ec != boost::asio::error::operation_aborted)
1094 {
1095 std::cerr << "Force power off async_wait failed: "
1096 << ec.message() << "\n";
1097 }
1098 return;
1099 }
1100 std::cerr << "PCH Power-button override failed. Issuing Unconditional "
1101 "Powerdown SMBus command.\n";
1102 const static constexpr size_t pchDevBusAddress = 3;
1103 const static constexpr size_t pchDevSlaveAddress = 0x44;
1104 const static constexpr size_t pchCmdReg = 0;
1105 const static constexpr size_t pchPowerDownCmd = 0x02;
1106 if (i2cSet(pchDevBusAddress, pchDevSlaveAddress, pchCmdReg,
1107 pchPowerDownCmd) < 0)
1108 {
1109 std::cerr << "Unconditional Powerdown command failed! Not sure "
1110 "what to do now.\n";
1111 }
1112 });
1113}
1114
1115static void reset()
1116{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001117 setGPIOOutputForMs(power_control::resetOutName, 0, resetPulseTimeMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001118}
1119
1120static void gracefulPowerOffTimerStart()
1121{
1122 std::cerr << "Graceful power-off timer started\n";
1123 gracefulPowerOffTimer.expires_after(
1124 std::chrono::milliseconds(gracefulPowerOffTimeMs));
1125 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1126 if (ec)
1127 {
1128 // operation_aborted is expected if timer is canceled before
1129 // completion.
1130 if (ec != boost::asio::error::operation_aborted)
1131 {
1132 std::cerr << "Graceful power-off async_wait failed: "
1133 << ec.message() << "\n";
1134 }
1135 std::cerr << "Graceful power-off timer canceled\n";
1136 return;
1137 }
1138 std::cerr << "Graceful power-off timer completed\n";
1139 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1140 });
1141}
1142
1143static void powerCycleTimerStart()
1144{
1145 std::cerr << "Power-cycle timer started\n";
1146 powerCycleTimer.expires_after(std::chrono::milliseconds(powerCycleTimeMs));
1147 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1148 if (ec)
1149 {
1150 // operation_aborted is expected if timer is canceled before
1151 // completion.
1152 if (ec != boost::asio::error::operation_aborted)
1153 {
1154 std::cerr << "Power-cycle async_wait failed: " << ec.message()
1155 << "\n";
1156 }
1157 std::cerr << "Power-cycle timer canceled\n";
1158 return;
1159 }
1160 std::cerr << "Power-cycle timer completed\n";
1161 sendPowerControlEvent(Event::powerCycleTimerExpired);
1162 });
1163}
1164
1165static void psPowerOKWatchdogTimerStart()
1166{
1167 std::cerr << "power supply power OK watchdog timer started\n";
1168 psPowerOKWatchdogTimer.expires_after(
1169 std::chrono::milliseconds(psPowerOKWatchdogTimeMs));
1170 psPowerOKWatchdogTimer.async_wait(
1171 [](const boost::system::error_code ec) {
1172 if (ec)
1173 {
1174 // operation_aborted is expected if timer is canceled before
1175 // completion.
1176 if (ec != boost::asio::error::operation_aborted)
1177 {
1178 std::cerr
1179 << "power supply power OK watchdog async_wait failed: "
1180 << ec.message() << "\n";
1181 }
1182 std::cerr << "power supply power OK watchdog timer canceled\n";
1183 return;
1184 }
1185 std::cerr << "power supply power OK watchdog timer expired\n";
1186 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1187 });
1188}
1189
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001190static void warmResetCheckTimerStart()
1191{
1192 std::cerr << "Warm reset check timer started\n";
1193 warmResetCheckTimer.expires_after(
1194 std::chrono::milliseconds(warmResetCheckTimeMs));
1195 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1196 if (ec)
1197 {
1198 // operation_aborted is expected if timer is canceled before
1199 // completion.
1200 if (ec != boost::asio::error::operation_aborted)
1201 {
1202 std::cerr << "Warm reset check async_wait failed: "
1203 << ec.message() << "\n";
1204 }
1205 std::cerr << "Warm reset check timer canceled\n";
1206 return;
1207 }
1208 std::cerr << "Warm reset check timer completed\n";
1209 sendPowerControlEvent(Event::warmResetDetected);
1210 });
1211}
1212
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001213static void pohCounterTimerStart()
1214{
1215 std::cerr << "POH timer started\n";
1216 // Set the time-out as 1 hour, to align with POH command in ipmid
1217 pohCounterTimer.expires_after(std::chrono::hours(1));
1218 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1219 if (ec)
1220 {
1221 // operation_aborted is expected if timer is canceled before
1222 // completion.
1223 if (ec != boost::asio::error::operation_aborted)
1224 {
1225 std::cerr << "POH timer async_wait failed: " << ec.message()
1226 << "\n";
1227 }
1228 std::cerr << "POH timer canceled\n";
1229 return;
1230 }
1231
1232 if (getHostState(powerState) !=
1233 "xyz.openbmc_project.State.Host.HostState.Running")
1234 {
1235 return;
1236 }
1237
1238 conn->async_method_call(
1239 [](boost::system::error_code ec,
1240 const std::variant<uint32_t>& pohCounterProperty) {
1241 if (ec)
1242 {
1243 std::cerr << "error to get poh counter\n";
1244 return;
1245 }
1246 const uint32_t* pohCounter =
1247 std::get_if<uint32_t>(&pohCounterProperty);
1248 if (pohCounter == nullptr)
1249 {
1250 std::cerr << "unable to read poh counter\n";
1251 return;
1252 }
1253
1254 conn->async_method_call(
1255 [](boost::system::error_code ec) {
1256 if (ec)
1257 {
1258 std::cerr << "failed to set poh counter\n";
1259 }
1260 },
1261 "xyz.openbmc_project.Settings",
1262 "/xyz/openbmc_project/state/chassis0",
1263 "org.freedesktop.DBus.Properties", "Set",
1264 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1265 std::variant<uint32_t>(*pohCounter + 1));
1266 },
1267 "xyz.openbmc_project.Settings",
1268 "/xyz/openbmc_project/state/chassis0",
1269 "org.freedesktop.DBus.Properties", "Get",
1270 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1271
1272 pohCounterTimerStart();
1273 });
1274}
1275
1276static void currentHostStateMonitor()
1277{
Yong Li8d660212019-12-27 10:18:10 +08001278 if (getHostState(powerState) ==
1279 "xyz.openbmc_project.State.Host.HostState.Running")
1280 {
1281 pohCounterTimerStart();
1282 // Clear the restart cause set for the next restart
1283 clearRestartCause();
1284 }
1285 else
1286 {
1287 pohCounterTimer.cancel();
1288 // Set the restart cause set for this restart
1289 setRestartCause();
1290 }
1291
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001292 static auto match = sdbusplus::bus::match::match(
1293 *conn,
1294 "type='signal',member='PropertiesChanged', "
1295 "interface='org.freedesktop.DBus.Properties', "
1296 "arg0namespace='xyz.openbmc_project.State.Host'",
1297 [](sdbusplus::message::message& message) {
1298 std::string intfName;
1299 std::map<std::string, std::variant<std::string>> properties;
1300
1301 message.read(intfName, properties);
1302
1303 std::variant<std::string> currentHostState;
1304
1305 try
1306 {
1307 currentHostState = properties.at("CurrentHostState");
1308 }
1309 catch (const std::out_of_range& e)
1310 {
1311 std::cerr << "Error in finding CurrentHostState property\n";
1312
1313 return;
1314 }
1315
1316 if (std::get<std::string>(currentHostState) ==
1317 "xyz.openbmc_project.State.Host.HostState.Running")
1318 {
1319 pohCounterTimerStart();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001320 // Clear the restart cause set for the next restart
1321 clearRestartCause();
Yong Li8d660212019-12-27 10:18:10 +08001322 sd_journal_send("MESSAGE=Host system DC power is on",
1323 "PRIORITY=%i", LOG_INFO,
1324 "REDFISH_MESSAGE_ID=%s",
1325 "OpenBMC.0.1.DCPowerOn", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001326 }
1327 else
1328 {
1329 pohCounterTimer.cancel();
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301330 // POST_COMPLETE GPIO event is not working in some platforms
1331 // when power state is changed to OFF. This resulted in
1332 // 'OperatingSystemState' to stay at 'Standby', even though
1333 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1334 // if HostState is trurned to OFF.
1335 osIface->set_property("OperatingSystemState",
1336 std::string("Inactive"));
1337
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001338 // Set the restart cause set for this restart
1339 setRestartCause();
Rashmi RV89f61312020-01-22 15:41:50 +05301340 resetACBootProperty();
Yong Li8d660212019-12-27 10:18:10 +08001341 sd_journal_send("MESSAGE=Host system DC power is off",
1342 "PRIORITY=%i", LOG_INFO,
1343 "REDFISH_MESSAGE_ID=%s",
1344 "OpenBMC.0.1.DCPowerOff", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001345 }
1346 });
1347}
1348
1349static void sioPowerGoodWatchdogTimerStart()
1350{
1351 std::cerr << "SIO power good watchdog timer started\n";
1352 sioPowerGoodWatchdogTimer.expires_after(
1353 std::chrono::milliseconds(sioPowerGoodWatchdogTimeMs));
1354 sioPowerGoodWatchdogTimer.async_wait(
1355 [](const boost::system::error_code ec) {
1356 if (ec)
1357 {
1358 // operation_aborted is expected if timer is canceled before
1359 // completion.
1360 if (ec != boost::asio::error::operation_aborted)
1361 {
1362 std::cerr << "SIO power good watchdog async_wait failed: "
1363 << ec.message() << "\n";
1364 }
1365 std::cerr << "SIO power good watchdog timer canceled\n";
1366 return;
1367 }
1368 std::cerr << "SIO power good watchdog timer completed\n";
1369 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1370 });
1371}
1372
1373static void powerStateOn(const Event event)
1374{
1375 logEvent(__FUNCTION__, event);
1376 switch (event)
1377 {
1378 case Event::psPowerOKDeAssert:
1379 setPowerState(PowerState::off);
1380 // DC power is unexpectedly lost, beep
1381 beep(beepPowerFail);
1382 break;
1383 case Event::sioS5Assert:
1384 setPowerState(PowerState::transitionToOff);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001385 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001386 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001387 case Event::postCompleteDeAssert:
1388 setPowerState(PowerState::checkForWarmReset);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001389 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001390 warmResetCheckTimerStart();
1391 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001392 case Event::powerButtonPressed:
1393 setPowerState(PowerState::gracefulTransitionToOff);
1394 gracefulPowerOffTimerStart();
1395 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001396 case Event::resetButtonPressed:
1397 setPowerState(PowerState::checkForWarmReset);
1398 warmResetCheckTimerStart();
1399 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001400 case Event::powerOffRequest:
1401 setPowerState(PowerState::transitionToOff);
1402 forcePowerOff();
1403 break;
1404 case Event::gracefulPowerOffRequest:
1405 setPowerState(PowerState::gracefulTransitionToOff);
1406 gracefulPowerOffTimerStart();
1407 gracefulPowerOff();
1408 break;
1409 case Event::powerCycleRequest:
1410 setPowerState(PowerState::transitionToCycleOff);
1411 forcePowerOff();
1412 break;
1413 case Event::gracefulPowerCycleRequest:
1414 setPowerState(PowerState::gracefulTransitionToCycleOff);
1415 gracefulPowerOffTimerStart();
1416 gracefulPowerOff();
1417 break;
1418 case Event::resetRequest:
1419 reset();
1420 break;
1421 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001422 phosphor::logging::log<phosphor::logging::level::INFO>(
1423 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001424 break;
1425 }
1426}
1427
1428static void powerStateWaitForPSPowerOK(const Event event)
1429{
1430 logEvent(__FUNCTION__, event);
1431 switch (event)
1432 {
1433 case Event::psPowerOKAssert:
1434 // Cancel any GPIO assertions held during the transition
1435 gpioAssertTimer.cancel();
1436 psPowerOKWatchdogTimer.cancel();
1437 sioPowerGoodWatchdogTimerStart();
1438 setPowerState(PowerState::waitForSIOPowerGood);
1439 break;
1440 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001441 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001442 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001443 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001444 case Event::sioPowerGoodAssert:
1445 psPowerOKWatchdogTimer.cancel();
1446 setPowerState(PowerState::on);
1447 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001448 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001449 phosphor::logging::log<phosphor::logging::level::INFO>(
1450 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001451 break;
1452 }
1453}
1454
1455static void powerStateWaitForSIOPowerGood(const Event event)
1456{
1457 logEvent(__FUNCTION__, event);
1458 switch (event)
1459 {
1460 case Event::sioPowerGoodAssert:
1461 sioPowerGoodWatchdogTimer.cancel();
1462 setPowerState(PowerState::on);
1463 break;
1464 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001465 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001466 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001467 break;
1468 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001469 phosphor::logging::log<phosphor::logging::level::INFO>(
1470 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001471 break;
1472 }
1473}
1474
1475static void powerStateOff(const Event event)
1476{
1477 logEvent(__FUNCTION__, event);
1478 switch (event)
1479 {
1480 case Event::psPowerOKAssert:
1481 setPowerState(PowerState::waitForSIOPowerGood);
1482 break;
1483 case Event::sioS5DeAssert:
1484 setPowerState(PowerState::waitForPSPowerOK);
1485 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001486 case Event::sioPowerGoodAssert:
1487 setPowerState(PowerState::on);
1488 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001489 case Event::powerButtonPressed:
1490 psPowerOKWatchdogTimerStart();
1491 setPowerState(PowerState::waitForPSPowerOK);
1492 break;
1493 case Event::powerOnRequest:
1494 psPowerOKWatchdogTimerStart();
1495 setPowerState(PowerState::waitForPSPowerOK);
1496 powerOn();
1497 break;
1498 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001499 phosphor::logging::log<phosphor::logging::level::INFO>(
1500 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001501 break;
1502 }
1503}
1504
1505static void powerStateTransitionToOff(const Event event)
1506{
1507 logEvent(__FUNCTION__, event);
1508 switch (event)
1509 {
1510 case Event::psPowerOKDeAssert:
1511 // Cancel any GPIO assertions held during the transition
1512 gpioAssertTimer.cancel();
1513 setPowerState(PowerState::off);
1514 break;
1515 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001516 phosphor::logging::log<phosphor::logging::level::INFO>(
1517 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001518 break;
1519 }
1520}
1521
1522static void powerStateGracefulTransitionToOff(const Event event)
1523{
1524 logEvent(__FUNCTION__, event);
1525 switch (event)
1526 {
1527 case Event::psPowerOKDeAssert:
1528 gracefulPowerOffTimer.cancel();
1529 setPowerState(PowerState::off);
1530 break;
1531 case Event::gracefulPowerOffTimerExpired:
1532 setPowerState(PowerState::on);
1533 break;
1534 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001535 phosphor::logging::log<phosphor::logging::level::INFO>(
1536 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001537 break;
1538 }
1539}
1540
1541static void powerStateCycleOff(const Event event)
1542{
1543 logEvent(__FUNCTION__, event);
1544 switch (event)
1545 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001546 case Event::psPowerOKAssert:
1547 powerCycleTimer.cancel();
1548 setPowerState(PowerState::waitForSIOPowerGood);
1549 break;
1550 case Event::sioS5DeAssert:
1551 powerCycleTimer.cancel();
1552 setPowerState(PowerState::waitForPSPowerOK);
1553 break;
1554 case Event::powerButtonPressed:
1555 powerCycleTimer.cancel();
1556 psPowerOKWatchdogTimerStart();
1557 setPowerState(PowerState::waitForPSPowerOK);
1558 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001559 case Event::powerCycleTimerExpired:
1560 psPowerOKWatchdogTimerStart();
1561 setPowerState(PowerState::waitForPSPowerOK);
1562 powerOn();
1563 break;
1564 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001565 phosphor::logging::log<phosphor::logging::level::INFO>(
1566 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001567 break;
1568 }
1569}
1570
1571static void powerStateTransitionToCycleOff(const Event event)
1572{
1573 logEvent(__FUNCTION__, event);
1574 switch (event)
1575 {
1576 case Event::psPowerOKDeAssert:
1577 // Cancel any GPIO assertions held during the transition
1578 gpioAssertTimer.cancel();
1579 setPowerState(PowerState::cycleOff);
1580 powerCycleTimerStart();
1581 break;
1582 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001583 phosphor::logging::log<phosphor::logging::level::INFO>(
1584 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001585 break;
1586 }
1587}
1588
1589static void powerStateGracefulTransitionToCycleOff(const Event event)
1590{
1591 logEvent(__FUNCTION__, event);
1592 switch (event)
1593 {
1594 case Event::psPowerOKDeAssert:
1595 gracefulPowerOffTimer.cancel();
1596 setPowerState(PowerState::cycleOff);
1597 powerCycleTimerStart();
1598 break;
1599 case Event::gracefulPowerOffTimerExpired:
1600 setPowerState(PowerState::on);
1601 break;
1602 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001603 phosphor::logging::log<phosphor::logging::level::INFO>(
1604 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001605 break;
1606 }
1607}
1608
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001609static void powerStateCheckForWarmReset(const Event event)
1610{
1611 logEvent(__FUNCTION__, event);
1612 switch (event)
1613 {
1614 case Event::sioS5Assert:
1615 warmResetCheckTimer.cancel();
1616 setPowerState(PowerState::transitionToOff);
1617 break;
1618 case Event::warmResetDetected:
1619 setPowerState(PowerState::on);
1620 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001621 case Event::psPowerOKDeAssert:
1622 warmResetCheckTimer.cancel();
1623 setPowerState(PowerState::off);
1624 // DC power is unexpectedly lost, beep
1625 beep(beepPowerFail);
1626 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001627 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001628 phosphor::logging::log<phosphor::logging::level::INFO>(
1629 "No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001630 break;
1631 }
1632}
1633
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001634static void psPowerOKHandler()
1635{
1636 gpiod::line_event gpioLineEvent = psPowerOKLine.event_read();
1637
1638 Event powerControlEvent =
1639 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
1640 ? Event::psPowerOKAssert
1641 : Event::psPowerOKDeAssert;
1642
1643 sendPowerControlEvent(powerControlEvent);
1644 psPowerOKEvent.async_wait(
1645 boost::asio::posix::stream_descriptor::wait_read,
1646 [](const boost::system::error_code ec) {
1647 if (ec)
1648 {
1649 std::cerr << "power supply power OK handler error: "
1650 << ec.message() << "\n";
1651 return;
1652 }
1653 psPowerOKHandler();
1654 });
1655}
1656
1657static void sioPowerGoodHandler()
1658{
1659 gpiod::line_event gpioLineEvent = sioPowerGoodLine.event_read();
1660
1661 Event powerControlEvent =
1662 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
1663 ? Event::sioPowerGoodAssert
1664 : Event::sioPowerGoodDeAssert;
1665
1666 sendPowerControlEvent(powerControlEvent);
1667 sioPowerGoodEvent.async_wait(
1668 boost::asio::posix::stream_descriptor::wait_read,
1669 [](const boost::system::error_code ec) {
1670 if (ec)
1671 {
1672 std::cerr << "SIO power good handler error: " << ec.message()
1673 << "\n";
1674 return;
1675 }
1676 sioPowerGoodHandler();
1677 });
1678}
1679
1680static void sioOnControlHandler()
1681{
1682 gpiod::line_event gpioLineEvent = sioOnControlLine.event_read();
1683
1684 bool sioOnControl =
1685 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE;
1686 std::cerr << "SIO_ONCONTROL value changed: " << sioOnControl << "\n";
1687 sioOnControlEvent.async_wait(
1688 boost::asio::posix::stream_descriptor::wait_read,
1689 [](const boost::system::error_code ec) {
1690 if (ec)
1691 {
1692 std::cerr << "SIO ONCONTROL handler error: " << ec.message()
1693 << "\n";
1694 return;
1695 }
1696 sioOnControlHandler();
1697 });
1698}
1699
1700static void sioS5Handler()
1701{
1702 gpiod::line_event gpioLineEvent = sioS5Line.event_read();
1703
1704 Event powerControlEvent =
1705 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE
1706 ? Event::sioS5Assert
1707 : Event::sioS5DeAssert;
1708
1709 sendPowerControlEvent(powerControlEvent);
1710 sioS5Event.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1711 [](const boost::system::error_code ec) {
1712 if (ec)
1713 {
1714 std::cerr << "SIO S5 handler error: "
1715 << ec.message() << "\n";
1716 return;
1717 }
1718 sioS5Handler();
1719 });
1720}
1721
1722static void powerButtonHandler()
1723{
1724 gpiod::line_event gpioLineEvent = powerButtonLine.event_read();
1725
1726 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1727 {
1728 powerButtonPressLog();
1729 powerButtonIface->set_property("ButtonPressed", true);
1730 if (!powerButtonMask)
1731 {
1732 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001733 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001734 }
1735 else
1736 {
1737 std::cerr << "power button press masked\n";
1738 }
1739 }
1740 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
1741 {
1742 powerButtonIface->set_property("ButtonPressed", false);
1743 }
1744 powerButtonEvent.async_wait(
1745 boost::asio::posix::stream_descriptor::wait_read,
1746 [](const boost::system::error_code ec) {
1747 if (ec)
1748 {
1749 std::cerr << "power button handler error: " << ec.message()
1750 << "\n";
1751 return;
1752 }
1753 powerButtonHandler();
1754 });
1755}
1756
1757static void resetButtonHandler()
1758{
1759 gpiod::line_event gpioLineEvent = resetButtonLine.event_read();
1760
1761 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1762 {
1763 resetButtonPressLog();
1764 resetButtonIface->set_property("ButtonPressed", true);
1765 if (!resetButtonMask)
1766 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001767 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001768 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001769 }
1770 else
1771 {
1772 std::cerr << "reset button press masked\n";
1773 }
1774 }
1775 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
1776 {
1777 resetButtonIface->set_property("ButtonPressed", false);
1778 }
1779 resetButtonEvent.async_wait(
1780 boost::asio::posix::stream_descriptor::wait_read,
1781 [](const boost::system::error_code ec) {
1782 if (ec)
1783 {
1784 std::cerr << "reset button handler error: " << ec.message()
1785 << "\n";
1786 return;
1787 }
1788 resetButtonHandler();
1789 });
1790}
1791
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07001792static constexpr auto systemdBusname = "org.freedesktop.systemd1";
1793static constexpr auto systemdPath = "/org/freedesktop/systemd1";
1794static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
1795static constexpr auto systemTargetName = "chassis-system-reset.target";
1796
1797void systemReset()
1798{
1799 conn->async_method_call(
1800 [](boost::system::error_code ec) {
1801 if (ec)
1802 {
1803 phosphor::logging::log<phosphor::logging::level::ERR>(
1804 "Failed to call chassis system reset",
1805 phosphor::logging::entry("ERR=%s", ec.message().c_str()));
1806 }
1807 },
1808 systemdBusname, systemdPath, systemdInterface, "StartUnit",
1809 systemTargetName, "replace");
1810}
1811
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001812static void nmiSetEnablePorperty(bool value)
1813{
1814 conn->async_method_call(
1815 [](boost::system::error_code ec) {
1816 if (ec)
1817 {
1818 std::cerr << "failed to set NMI source\n";
1819 }
1820 },
Chen Yugang303bd582019-11-01 08:45:06 +08001821 "xyz.openbmc_project.Settings",
1822 "/xyz/openbmc_project/Chassis/Control/NMISource",
1823 "org.freedesktop.DBus.Properties", "Set",
1824 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
1825 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001826}
1827
1828static void nmiReset(void)
1829{
1830 static constexpr const uint8_t value = 1;
1831 const static constexpr int nmiOutPulseTimeMs = 200;
1832
1833 std::cerr << "NMI out action \n";
1834 nmiOutLine.set_value(value);
1835 std::cerr << nmiOutName << " set to " << std::to_string(value) << "\n";
1836 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
1837 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1838 // restore the NMI_OUT GPIO line back to the opposite value
1839 nmiOutLine.set_value(!value);
1840 std::cerr << nmiOutName << " released\n";
1841 if (ec)
1842 {
1843 // operation_aborted is expected if timer is canceled before
1844 // completion.
1845 if (ec != boost::asio::error::operation_aborted)
1846 {
1847 std::cerr << nmiOutName << " async_wait failed: " + ec.message()
1848 << "\n";
1849 }
1850 }
1851 });
1852 // log to redfish
1853 nmiDiagIntLog();
1854 std::cerr << "NMI out action completed\n";
1855 // reset Enable Property
1856 nmiSetEnablePorperty(false);
1857}
1858
1859static void nmiSourcePropertyMonitor(void)
1860{
1861 std::cerr << " NMI Source Property Monitor \n";
1862
1863 static std::unique_ptr<sdbusplus::bus::match::match> nmiSourceMatch =
1864 std::make_unique<sdbusplus::bus::match::match>(
1865 *conn,
1866 "type='signal',interface='org.freedesktop.DBus.Properties',"
Chen Yugang303bd582019-11-01 08:45:06 +08001867 "member='PropertiesChanged',arg0namespace='xyz.openbmc_project."
1868 "Chassis.Control."
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001869 "NMISource'",
1870 [](sdbusplus::message::message& msg) {
1871 std::string interfaceName;
1872 boost::container::flat_map<std::string,
1873 std::variant<bool, std::string>>
1874 propertiesChanged;
1875 std::string state;
1876 bool value = true;
1877 try
1878 {
1879 msg.read(interfaceName, propertiesChanged);
1880 if (propertiesChanged.begin()->first == "Enabled")
1881 {
1882 value =
1883 std::get<bool>(propertiesChanged.begin()->second);
1884 std::cerr
1885 << " NMI Enabled propertiesChanged value: " << value
1886 << "\n";
1887 nmiEnabled = value;
1888 if (nmiEnabled)
1889 {
1890 nmiReset();
1891 }
1892 }
1893 }
1894 catch (std::exception& e)
1895 {
1896 std::cerr << "Unable to read NMI source\n";
1897 return;
1898 }
1899 });
1900}
1901
1902static void setNmiSource()
1903{
1904 conn->async_method_call(
1905 [](boost::system::error_code ec) {
1906 if (ec)
1907 {
1908 std::cerr << "failed to set NMI source\n";
1909 }
1910 },
Chen Yugang303bd582019-11-01 08:45:06 +08001911 "xyz.openbmc_project.Settings",
1912 "/xyz/openbmc_project/Chassis/Control/NMISource",
1913 "org.freedesktop.DBus.Properties", "Set",
1914 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
1915 std::variant<std::string>{"xyz.openbmc_project.Chassis.Control."
1916 "NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001917 // set Enable Property
1918 nmiSetEnablePorperty(true);
1919}
1920
1921static void nmiButtonHandler()
1922{
1923 gpiod::line_event gpioLineEvent = nmiButtonLine.event_read();
1924
1925 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1926 {
1927 nmiButtonPressLog();
1928 nmiButtonIface->set_property("ButtonPressed", true);
1929 if (nmiButtonMasked)
1930 {
1931 std::cerr << "NMI button press masked\n";
1932 }
1933 else
1934 {
1935 setNmiSource();
1936 }
1937 }
1938 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
1939 {
1940 nmiButtonIface->set_property("ButtonPressed", false);
1941 }
1942 nmiButtonEvent.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1943 [](const boost::system::error_code ec) {
1944 if (ec)
1945 {
1946 std::cerr << "NMI button handler error: "
1947 << ec.message() << "\n";
1948 return;
1949 }
1950 nmiButtonHandler();
1951 });
1952}
1953
1954static void idButtonHandler()
1955{
1956 gpiod::line_event gpioLineEvent = idButtonLine.event_read();
1957
1958 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1959 {
1960 idButtonIface->set_property("ButtonPressed", true);
1961 }
1962 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
1963 {
1964 idButtonIface->set_property("ButtonPressed", false);
1965 }
1966 idButtonEvent.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1967 [](const boost::system::error_code& ec) {
1968 if (ec)
1969 {
1970 std::cerr << "ID button handler error: "
1971 << ec.message() << "\n";
1972 return;
1973 }
1974 idButtonHandler();
1975 });
1976}
1977
1978static void postCompleteHandler()
1979{
1980 gpiod::line_event gpioLineEvent = postCompleteLine.event_read();
1981
1982 bool postComplete =
1983 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001984 if (postComplete)
1985 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001986 sendPowerControlEvent(Event::postCompleteAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001987 osIface->set_property("OperatingSystemState", std::string("Standby"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001988 }
1989 else
1990 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001991 sendPowerControlEvent(Event::postCompleteDeAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001992 osIface->set_property("OperatingSystemState", std::string("Inactive"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001993 }
1994 postCompleteEvent.async_wait(
1995 boost::asio::posix::stream_descriptor::wait_read,
1996 [](const boost::system::error_code ec) {
1997 if (ec)
1998 {
1999 std::cerr << "POST complete handler error: " << ec.message()
2000 << "\n";
2001 return;
2002 }
2003 postCompleteHandler();
2004 });
2005}
2006} // namespace power_control
2007
2008int main(int argc, char* argv[])
2009{
2010 std::cerr << "Start Chassis power control service...\n";
2011 power_control::conn =
2012 std::make_shared<sdbusplus::asio::connection>(power_control::io);
2013
2014 // Request all the dbus names
2015 power_control::conn->request_name("xyz.openbmc_project.State.Host");
2016 power_control::conn->request_name("xyz.openbmc_project.State.Chassis");
2017 power_control::conn->request_name(
2018 "xyz.openbmc_project.State.OperatingSystem");
2019 power_control::conn->request_name("xyz.openbmc_project.Chassis.Buttons");
Chen Yugang174ec662019-08-19 19:58:49 +08002020 power_control::conn->request_name("xyz.openbmc_project.Control.Host.NMI");
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002021 power_control::conn->request_name(
2022 "xyz.openbmc_project.Control.Host.RestartCause");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002023
2024 // Request PS_PWROK GPIO events
2025 if (!power_control::requestGPIOEvents(
2026 "PS_PWROK", power_control::psPowerOKHandler,
2027 power_control::psPowerOKLine, power_control::psPowerOKEvent))
2028 {
2029 return -1;
2030 }
2031
2032 // Request SIO_POWER_GOOD GPIO events
2033 if (!power_control::requestGPIOEvents(
2034 "SIO_POWER_GOOD", power_control::sioPowerGoodHandler,
2035 power_control::sioPowerGoodLine, power_control::sioPowerGoodEvent))
2036 {
2037 return -1;
2038 }
2039
2040 // Request SIO_ONCONTROL GPIO events
2041 if (!power_control::requestGPIOEvents(
2042 "SIO_ONCONTROL", power_control::sioOnControlHandler,
2043 power_control::sioOnControlLine, power_control::sioOnControlEvent))
2044 {
2045 return -1;
2046 }
2047
2048 // Request SIO_S5 GPIO events
2049 if (!power_control::requestGPIOEvents("SIO_S5", power_control::sioS5Handler,
2050 power_control::sioS5Line,
2051 power_control::sioS5Event))
2052 {
2053 return -1;
2054 }
2055
2056 // Request POWER_BUTTON GPIO events
2057 if (!power_control::requestGPIOEvents(
2058 "POWER_BUTTON", power_control::powerButtonHandler,
2059 power_control::powerButtonLine, power_control::powerButtonEvent))
2060 {
2061 return -1;
2062 }
2063
2064 // Request RESET_BUTTON GPIO events
2065 if (!power_control::requestGPIOEvents(
2066 "RESET_BUTTON", power_control::resetButtonHandler,
2067 power_control::resetButtonLine, power_control::resetButtonEvent))
2068 {
2069 return -1;
2070 }
2071
2072 // Request NMI_BUTTON GPIO events
Vijay Khemka33a532d2019-11-14 16:50:35 -08002073 power_control::requestGPIOEvents(
2074 "NMI_BUTTON", power_control::nmiButtonHandler,
2075 power_control::nmiButtonLine, power_control::nmiButtonEvent);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002076
2077 // Request ID_BUTTON GPIO events
Vijay Khemka33a532d2019-11-14 16:50:35 -08002078 power_control::requestGPIOEvents(
2079 "ID_BUTTON", power_control::idButtonHandler,
2080 power_control::idButtonLine, power_control::idButtonEvent);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002081
2082 // Request POST_COMPLETE GPIO events
2083 if (!power_control::requestGPIOEvents(
2084 "POST_COMPLETE", power_control::postCompleteHandler,
2085 power_control::postCompleteLine, power_control::postCompleteEvent))
2086 {
2087 return -1;
2088 }
2089
2090 // initialize NMI_OUT GPIO.
Vijay Khemka33a532d2019-11-14 16:50:35 -08002091 power_control::setGPIOOutput(power_control::nmiOutName, 0,
2092 power_control::nmiOutLine);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002093
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002094 // Initialize POWER_OUT and RESET_OUT GPIO.
2095 gpiod::line line;
2096 if (!power_control::setGPIOOutput(power_control::powerOutName, 1, line))
2097 {
2098 return -1;
2099 }
2100
2101 if (!power_control::setGPIOOutput(power_control::resetOutName, 1, line))
2102 {
2103 return -1;
2104 }
2105
2106 // Release line
2107 line.reset();
2108
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002109 // Initialize the power state
2110 power_control::powerState = power_control::PowerState::off;
2111 // Check power good
2112 if (power_control::psPowerOKLine.get_value() > 0)
2113 {
2114 power_control::powerState = power_control::PowerState::on;
2115 }
2116
2117 // Initialize the power state storage
2118 if (power_control::initializePowerStateStorage() < 0)
2119 {
2120 return -1;
2121 }
2122
2123 // Check if we need to start the Power Restore policy
2124 power_control::powerRestorePolicyCheck();
2125
Vijay Khemka33a532d2019-11-14 16:50:35 -08002126 if (power_control::nmiOutLine)
2127 power_control::nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002128
2129 std::cerr << "Initializing power state. ";
2130 power_control::logStateTransition(power_control::powerState);
2131
2132 // Power Control Service
2133 sdbusplus::asio::object_server hostServer =
2134 sdbusplus::asio::object_server(power_control::conn);
2135
2136 // Power Control Interface
2137 power_control::hostIface = hostServer.add_interface(
2138 "/xyz/openbmc_project/state/host0", "xyz.openbmc_project.State.Host");
2139
2140 power_control::hostIface->register_property(
2141 "RequestedHostTransition",
2142 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2143 [](const std::string& requested, std::string& resp) {
2144 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2145 {
2146 sendPowerControlEvent(
2147 power_control::Event::gracefulPowerOffRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002148 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002149 }
2150 else if (requested ==
2151 "xyz.openbmc_project.State.Host.Transition.On")
2152 {
2153 sendPowerControlEvent(power_control::Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002154 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002155 }
2156 else if (requested ==
2157 "xyz.openbmc_project.State.Host.Transition.Reboot")
2158 {
Jason M. Billse7520ba2020-01-31 11:19:03 -08002159 sendPowerControlEvent(power_control::Event::powerCycleRequest);
2160 addRestartCause(power_control::RestartCause::command);
2161 }
2162 else if (requested == "xyz.openbmc_project.State.Host.Transition."
2163 "GracefulWarmReboot")
2164 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002165 sendPowerControlEvent(
2166 power_control::Event::gracefulPowerCycleRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002167 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002168 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002169 else if (requested == "xyz.openbmc_project.State.Host.Transition."
2170 "ForceWarmReboot")
2171 {
2172 sendPowerControlEvent(power_control::Event::resetRequest);
2173 addRestartCause(power_control::RestartCause::command);
2174 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002175 else
2176 {
2177 std::cerr << "Unrecognized host state transition request.\n";
2178 throw std::invalid_argument("Unrecognized Transition Request");
2179 return 0;
2180 }
2181 resp = requested;
2182 return 1;
2183 });
2184 power_control::hostIface->register_property(
2185 "CurrentHostState",
2186 std::string(power_control::getHostState(power_control::powerState)));
2187
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002188 power_control::hostIface->initialize();
2189
2190 // Chassis Control Service
2191 sdbusplus::asio::object_server chassisServer =
2192 sdbusplus::asio::object_server(power_control::conn);
2193
2194 // Chassis Control Interface
2195 power_control::chassisIface =
2196 chassisServer.add_interface("/xyz/openbmc_project/state/chassis0",
2197 "xyz.openbmc_project.State.Chassis");
2198
2199 power_control::chassisIface->register_property(
2200 "RequestedPowerTransition",
2201 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
2202 [](const std::string& requested, std::string& resp) {
2203 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
2204 {
2205 sendPowerControlEvent(power_control::Event::powerOffRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002206 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002207 }
2208 else if (requested ==
2209 "xyz.openbmc_project.State.Chassis.Transition.On")
2210 {
2211 sendPowerControlEvent(power_control::Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002212 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002213 }
2214 else if (requested ==
2215 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2216 {
2217 sendPowerControlEvent(power_control::Event::powerCycleRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002218 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002219 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002220 else
2221 {
2222 std::cerr << "Unrecognized chassis state transition request.\n";
2223 throw std::invalid_argument("Unrecognized Transition Request");
2224 return 0;
2225 }
2226 resp = requested;
2227 return 1;
2228 });
2229 power_control::chassisIface->register_property(
2230 "CurrentPowerState",
2231 std::string(power_control::getChassisState(power_control::powerState)));
2232 power_control::chassisIface->register_property(
2233 "LastStateChangeTime", power_control::getCurrentTimeMs());
2234
2235 power_control::chassisIface->initialize();
2236
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002237 // Chassis System Service
2238 sdbusplus::asio::object_server chassisSysServer =
2239 sdbusplus::asio::object_server(power_control::conn);
2240
2241 // Chassis System Interface
2242 power_control::chassisSysIface = chassisSysServer.add_interface(
2243 "/xyz/openbmc_project/state/chassis_system0",
2244 "xyz.openbmc_project.State.Chassis");
2245
2246 power_control::chassisSysIface->register_property(
2247 "RequestedPowerTransition",
2248 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
2249 [](const std::string& requested, std::string& resp) {
2250 if (requested ==
2251 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2252 {
2253 power_control::systemReset();
2254 addRestartCause(power_control::RestartCause::command);
2255 }
2256 else
2257 {
2258 std::cerr << "Unrecognized chassis system state transition "
2259 "request.\n";
2260 throw std::invalid_argument("Unrecognized Transition Request");
2261 return 0;
2262 }
2263 resp = requested;
2264 return 1;
2265 });
2266 power_control::chassisSysIface->register_property(
2267 "CurrentPowerState",
2268 std::string(power_control::getChassisState(power_control::powerState)));
2269 power_control::chassisSysIface->register_property(
2270 "LastStateChangeTime", power_control::getCurrentTimeMs());
2271
2272 power_control::chassisSysIface->initialize();
2273
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002274 // Buttons Service
2275 sdbusplus::asio::object_server buttonsServer =
2276 sdbusplus::asio::object_server(power_control::conn);
2277
2278 // Power Button Interface
2279 power_control::powerButtonIface = buttonsServer.add_interface(
2280 "/xyz/openbmc_project/chassis/buttons/power",
2281 "xyz.openbmc_project.Chassis.Buttons");
2282
2283 power_control::powerButtonIface->register_property(
2284 "ButtonMasked", false, [](const bool requested, bool& current) {
2285 if (requested)
2286 {
2287 if (power_control::powerButtonMask)
2288 {
2289 return 1;
2290 }
2291 if (!power_control::setGPIOOutput(
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002292 power_control::powerOutName, 1,
2293 power_control::powerButtonMask))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002294 {
2295 throw std::runtime_error("Failed to request GPIO");
2296 return 0;
2297 }
2298 std::cerr << "Power Button Masked.\n";
2299 }
2300 else
2301 {
2302 if (!power_control::powerButtonMask)
2303 {
2304 return 1;
2305 }
2306 std::cerr << "Power Button Un-masked\n";
2307 power_control::powerButtonMask.reset();
2308 }
2309 // Update the mask setting
2310 current = requested;
2311 return 1;
2312 });
2313
2314 // Check power button state
2315 bool powerButtonPressed = power_control::powerButtonLine.get_value() == 0;
2316 power_control::powerButtonIface->register_property("ButtonPressed",
2317 powerButtonPressed);
2318
2319 power_control::powerButtonIface->initialize();
2320
2321 // Reset Button Interface
2322 power_control::resetButtonIface = buttonsServer.add_interface(
2323 "/xyz/openbmc_project/chassis/buttons/reset",
2324 "xyz.openbmc_project.Chassis.Buttons");
2325
2326 power_control::resetButtonIface->register_property(
2327 "ButtonMasked", false, [](const bool requested, bool& current) {
2328 if (requested)
2329 {
2330 if (power_control::resetButtonMask)
2331 {
2332 return 1;
2333 }
2334 if (!power_control::setGPIOOutput(
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002335 power_control::resetOutName, 1,
2336 power_control::resetButtonMask))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002337 {
2338 throw std::runtime_error("Failed to request GPIO");
2339 return 0;
2340 }
2341 std::cerr << "Reset Button Masked.\n";
2342 }
2343 else
2344 {
2345 if (!power_control::resetButtonMask)
2346 {
2347 return 1;
2348 }
2349 std::cerr << "Reset Button Un-masked\n";
2350 power_control::resetButtonMask.reset();
2351 }
2352 // Update the mask setting
2353 current = requested;
2354 return 1;
2355 });
2356
2357 // Check reset button state
2358 bool resetButtonPressed = power_control::resetButtonLine.get_value() == 0;
2359 power_control::resetButtonIface->register_property("ButtonPressed",
2360 resetButtonPressed);
2361
2362 power_control::resetButtonIface->initialize();
2363
Vijay Khemka33a532d2019-11-14 16:50:35 -08002364 if (power_control::nmiButtonLine)
2365 {
2366 // NMI Button Interface
2367 power_control::nmiButtonIface = buttonsServer.add_interface(
2368 "/xyz/openbmc_project/chassis/buttons/nmi",
2369 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002370
Vijay Khemka33a532d2019-11-14 16:50:35 -08002371 power_control::nmiButtonIface->register_property(
2372 "ButtonMasked", false, [](const bool requested, bool& current) {
2373 if (power_control::nmiButtonMasked == requested)
2374 {
2375 // NMI button mask is already set as requested, so no change
2376 return 1;
2377 }
2378 if (requested)
2379 {
2380 std::cerr << "NMI Button Masked.\n";
2381 power_control::nmiButtonMasked = true;
2382 }
2383 else
2384 {
2385 std::cerr << "NMI Button Un-masked.\n";
2386 power_control::nmiButtonMasked = false;
2387 }
2388 // Update the mask setting
2389 current = power_control::nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002390 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08002391 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002392
Vijay Khemka33a532d2019-11-14 16:50:35 -08002393 // Check NMI button state
2394 bool nmiButtonPressed = power_control::nmiButtonLine.get_value() == 0;
2395 power_control::nmiButtonIface->register_property("ButtonPressed",
2396 nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002397
Vijay Khemka33a532d2019-11-14 16:50:35 -08002398 power_control::nmiButtonIface->initialize();
2399 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002400
Vijay Khemka33a532d2019-11-14 16:50:35 -08002401 if (power_control::nmiOutLine)
2402 {
2403 // NMI out Service
2404 sdbusplus::asio::object_server nmiOutServer =
2405 sdbusplus::asio::object_server(power_control::conn);
Chen Yugang174ec662019-08-19 19:58:49 +08002406
Vijay Khemka33a532d2019-11-14 16:50:35 -08002407 // NMI out Interface
2408 power_control::nmiOutIface =
2409 nmiOutServer.add_interface("/xyz/openbmc_project/control/host0/nmi",
2410 "xyz.openbmc_project.Control.Host.NMI");
2411 power_control::nmiOutIface->register_method("NMI",
2412 power_control::nmiReset);
2413 power_control::nmiOutIface->initialize();
2414 }
Chen Yugang174ec662019-08-19 19:58:49 +08002415
Vijay Khemka33a532d2019-11-14 16:50:35 -08002416 if (power_control::idButtonLine)
2417 {
2418 // ID Button Interface
2419 power_control::idButtonIface = buttonsServer.add_interface(
2420 "/xyz/openbmc_project/chassis/buttons/id",
2421 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002422
Vijay Khemka33a532d2019-11-14 16:50:35 -08002423 // Check ID button state
2424 bool idButtonPressed = power_control::idButtonLine.get_value() == 0;
2425 power_control::idButtonIface->register_property("ButtonPressed",
2426 idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002427
Vijay Khemka33a532d2019-11-14 16:50:35 -08002428 power_control::idButtonIface->initialize();
2429 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002430
2431 // OS State Service
2432 sdbusplus::asio::object_server osServer =
2433 sdbusplus::asio::object_server(power_control::conn);
2434
2435 // OS State Interface
2436 power_control::osIface = osServer.add_interface(
2437 "/xyz/openbmc_project/state/os",
2438 "xyz.openbmc_project.State.OperatingSystem.Status");
2439
2440 // Get the initial OS state based on POST complete
2441 // 0: Asserted, OS state is "Standby" (ready to boot)
2442 // 1: De-Asserted, OS state is "Inactive"
2443 std::string osState = power_control::postCompleteLine.get_value() > 0
2444 ? "Inactive"
2445 : "Standby";
2446
2447 power_control::osIface->register_property("OperatingSystemState",
2448 std::string(osState));
2449
2450 power_control::osIface->initialize();
2451
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002452 // Restart Cause Service
2453 sdbusplus::asio::object_server restartCauseServer =
2454 sdbusplus::asio::object_server(power_control::conn);
2455
2456 // Restart Cause Interface
2457 power_control::restartCauseIface = restartCauseServer.add_interface(
2458 "/xyz/openbmc_project/control/host0/restart_cause",
2459 "xyz.openbmc_project.Control.Host.RestartCause");
2460
2461 power_control::restartCauseIface->register_property(
2462 "RestartCause",
2463 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
2464
2465 power_control::restartCauseIface->register_property(
2466 "RequestedRestartCause",
2467 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
2468 [](const std::string& requested, std::string& resp) {
2469 if (requested ==
2470 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
2471 {
2472 power_control::addRestartCause(
2473 power_control::RestartCause::watchdog);
2474 }
2475 else
2476 {
2477 throw std::invalid_argument(
2478 "Unrecognized RestartCause Request");
2479 return 0;
2480 }
2481
2482 std::cerr << "RestartCause requested: " << requested << "\n";
2483 resp = requested;
2484 return 1;
2485 });
2486
2487 power_control::restartCauseIface->initialize();
2488
Yong Li8d660212019-12-27 10:18:10 +08002489 power_control::currentHostStateMonitor();
2490
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002491 power_control::io.run();
2492
2493 return 0;
2494}