blob: 30844d3863c53eb208f1fa12f32c3b9ef903968f [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
Jason M. Billse63dea02020-08-27 12:07:35 -070021#include <boost/asio/io_service.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070022#include <boost/asio/posix/stream_descriptor.hpp>
Jason M. Billse63dea02020-08-27 12:07:35 -070023#include <boost/asio/steady_timer.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070024#include <boost/container/flat_map.hpp>
Jason M. Bills7d4aaac2019-09-19 14:03:44 -070025#include <boost/container/flat_set.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070026#include <gpiod.hpp>
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053027#include <nlohmann/json.hpp>
Vijay Khemkafc1ecc52020-04-01 10:49:28 -070028#include <phosphor-logging/log.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070029#include <sdbusplus/asio/object_server.hpp>
Vijay Khemka2b6f4422020-05-29 11:13:23 -070030
31#include <filesystem>
32#include <fstream>
33#include <iostream>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070034#include <string_view>
35
36namespace power_control
37{
38static boost::asio::io_service io;
39std::shared_ptr<sdbusplus::asio::connection> conn;
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053040
41static std::string node = "0";
42
43static std::string powerOutName;
44static std::string powerOkName;
45static std::string resetOutName;
46static std::string nmiOutName;
47static std::string sioPwrGoodName;
48static std::string sioOnControlName;
49static std::string sioS5Name;
50static std::string postCompleteName;
51static std::string powerButtonName;
52static std::string resetButtonName;
53static std::string idButtonName;
54static std::string nmiButtonName;
55
Ed Tanousf61ca6f2019-08-15 15:09:05 -070056static std::shared_ptr<sdbusplus::asio::dbus_interface> hostIface;
57static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisIface;
Vijay Khemka75ad0cf2020-04-02 15:23:51 -070058static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSysIface;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070059static std::shared_ptr<sdbusplus::asio::dbus_interface> powerButtonIface;
60static std::shared_ptr<sdbusplus::asio::dbus_interface> resetButtonIface;
61static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiButtonIface;
62static std::shared_ptr<sdbusplus::asio::dbus_interface> osIface;
63static std::shared_ptr<sdbusplus::asio::dbus_interface> idButtonIface;
Chen Yugang174ec662019-08-19 19:58:49 +080064static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiOutIface;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -070065static std::shared_ptr<sdbusplus::asio::dbus_interface> restartCauseIface;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070066
67static gpiod::line powerButtonMask;
68static gpiod::line resetButtonMask;
69static bool nmiButtonMasked = false;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070070
71const static constexpr int powerPulseTimeMs = 200;
72const static constexpr int forceOffPulseTimeMs = 15000;
73const static constexpr int resetPulseTimeMs = 500;
Jason M. Billsfc9408a2020-01-31 14:54:17 -080074const static constexpr int powerCycleTimeMs = 5000;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070075const static constexpr int sioPowerGoodWatchdogTimeMs = 1000;
76const static constexpr int psPowerOKWatchdogTimeMs = 8000;
77const static constexpr int gracefulPowerOffTimeMs = 60000;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -070078const static constexpr int warmResetCheckTimeMs = 500;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070079const static constexpr int buttonMaskTimeMs = 60000;
80const static constexpr int powerOffSaveTimeMs = 7000;
81
82const static std::filesystem::path powerControlDir = "/var/lib/power-control";
83const static constexpr std::string_view powerStateFile = "power-state";
84
85static bool nmiEnabled = true;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070086
87// Timers
88// Time holding GPIOs asserted
89static boost::asio::steady_timer gpioAssertTimer(io);
90// Time between off and on during a power cycle
91static boost::asio::steady_timer powerCycleTimer(io);
92// Time OS gracefully powering off
93static boost::asio::steady_timer gracefulPowerOffTimer(io);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -070094// Time the warm reset check
95static boost::asio::steady_timer warmResetCheckTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -070096// Time power supply power OK assertion on power-on
97static boost::asio::steady_timer psPowerOKWatchdogTimer(io);
98// Time SIO power good assertion on power-on
99static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io);
100// Time power-off state save for power loss tracking
101static boost::asio::steady_timer powerStateSaveTimer(io);
102// POH timer
103static boost::asio::steady_timer pohCounterTimer(io);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700104// Time when to allow restart cause updates
105static boost::asio::steady_timer restartCauseTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700106
107// GPIO Lines and Event Descriptors
108static gpiod::line psPowerOKLine;
109static boost::asio::posix::stream_descriptor psPowerOKEvent(io);
110static gpiod::line sioPowerGoodLine;
111static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io);
112static gpiod::line sioOnControlLine;
113static boost::asio::posix::stream_descriptor sioOnControlEvent(io);
114static gpiod::line sioS5Line;
115static boost::asio::posix::stream_descriptor sioS5Event(io);
116static gpiod::line powerButtonLine;
117static boost::asio::posix::stream_descriptor powerButtonEvent(io);
118static gpiod::line resetButtonLine;
119static boost::asio::posix::stream_descriptor resetButtonEvent(io);
120static gpiod::line nmiButtonLine;
121static boost::asio::posix::stream_descriptor nmiButtonEvent(io);
122static gpiod::line idButtonLine;
123static boost::asio::posix::stream_descriptor idButtonEvent(io);
124static gpiod::line postCompleteLine;
125static boost::asio::posix::stream_descriptor postCompleteEvent(io);
126static gpiod::line nmiOutLine;
127
128static constexpr uint8_t beepPowerFail = 8;
129
130static void beep(const uint8_t& beepPriority)
131{
132 std::cerr << "Beep with priority: " << (unsigned)beepPriority << "\n";
133
134 conn->async_method_call(
135 [](boost::system::error_code ec) {
136 if (ec)
137 {
138 std::cerr << "beep returned error with "
139 "async_method_call (ec = "
140 << ec << ")\n";
141 return;
142 }
143 },
144 "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
145 "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
146}
147
148enum class PowerState
149{
150 on,
151 waitForPSPowerOK,
152 waitForSIOPowerGood,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700153 off,
154 transitionToOff,
155 gracefulTransitionToOff,
156 cycleOff,
157 transitionToCycleOff,
158 gracefulTransitionToCycleOff,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700159 checkForWarmReset,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700160};
161static PowerState powerState;
162static std::string getPowerStateName(PowerState state)
163{
164 switch (state)
165 {
166 case PowerState::on:
167 return "On";
168 break;
169 case PowerState::waitForPSPowerOK:
170 return "Wait for Power Supply Power OK";
171 break;
172 case PowerState::waitForSIOPowerGood:
173 return "Wait for SIO Power Good";
174 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700175 case PowerState::off:
176 return "Off";
177 break;
178 case PowerState::transitionToOff:
179 return "Transition to Off";
180 break;
181 case PowerState::gracefulTransitionToOff:
182 return "Graceful Transition to Off";
183 break;
184 case PowerState::cycleOff:
185 return "Power Cycle Off";
186 break;
187 case PowerState::transitionToCycleOff:
188 return "Transition to Power Cycle Off";
189 break;
190 case PowerState::gracefulTransitionToCycleOff:
191 return "Graceful Transition to Power Cycle Off";
192 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700193 case PowerState::checkForWarmReset:
194 return "Check for Warm Reset";
195 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700196 default:
197 return "unknown state: " + std::to_string(static_cast<int>(state));
198 break;
199 }
200}
201static void logStateTransition(const PowerState state)
202{
Vijay Khemkad6c5ad12020-05-27 14:57:52 -0700203 std::string logMsg =
204 "Host0: Moving to \"" + getPowerStateName(state) + "\" state";
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700205 phosphor::logging::log<phosphor::logging::level::INFO>(
206 logMsg.c_str(),
Vijay Khemkad6c5ad12020-05-27 14:57:52 -0700207 phosphor::logging::entry("STATE=%s", getPowerStateName(state).c_str()),
208 phosphor::logging::entry("HOST=0"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700209}
210
211enum class Event
212{
213 psPowerOKAssert,
214 psPowerOKDeAssert,
215 sioPowerGoodAssert,
216 sioPowerGoodDeAssert,
217 sioS5Assert,
218 sioS5DeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700219 postCompleteAssert,
220 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700221 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700222 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700223 powerCycleTimerExpired,
224 psPowerOKWatchdogTimerExpired,
225 sioPowerGoodWatchdogTimerExpired,
226 gracefulPowerOffTimerExpired,
227 powerOnRequest,
228 powerOffRequest,
229 powerCycleRequest,
230 resetRequest,
231 gracefulPowerOffRequest,
232 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700233 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700234};
235static std::string getEventName(Event event)
236{
237 switch (event)
238 {
239 case Event::psPowerOKAssert:
240 return "power supply power OK assert";
241 break;
242 case Event::psPowerOKDeAssert:
243 return "power supply power OK de-assert";
244 break;
245 case Event::sioPowerGoodAssert:
246 return "SIO power good assert";
247 break;
248 case Event::sioPowerGoodDeAssert:
249 return "SIO power good de-assert";
250 break;
251 case Event::sioS5Assert:
252 return "SIO S5 assert";
253 break;
254 case Event::sioS5DeAssert:
255 return "SIO S5 de-assert";
256 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700257 case Event::postCompleteAssert:
258 return "POST Complete assert";
259 break;
260 case Event::postCompleteDeAssert:
261 return "POST Complete de-assert";
262 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700263 case Event::powerButtonPressed:
264 return "power button pressed";
265 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700266 case Event::resetButtonPressed:
267 return "reset button pressed";
268 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700269 case Event::powerCycleTimerExpired:
270 return "power cycle timer expired";
271 break;
272 case Event::psPowerOKWatchdogTimerExpired:
273 return "power supply power OK watchdog timer expired";
274 break;
275 case Event::sioPowerGoodWatchdogTimerExpired:
276 return "SIO power good watchdog timer expired";
277 break;
278 case Event::gracefulPowerOffTimerExpired:
279 return "graceful power-off timer expired";
280 break;
281 case Event::powerOnRequest:
282 return "power-on request";
283 break;
284 case Event::powerOffRequest:
285 return "power-off request";
286 break;
287 case Event::powerCycleRequest:
288 return "power-cycle request";
289 break;
290 case Event::resetRequest:
291 return "reset request";
292 break;
293 case Event::gracefulPowerOffRequest:
294 return "graceful power-off request";
295 break;
296 case Event::gracefulPowerCycleRequest:
297 return "graceful power-cycle request";
298 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700299 case Event::warmResetDetected:
300 return "warm reset detected";
301 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700302 default:
303 return "unknown event: " + std::to_string(static_cast<int>(event));
304 break;
305 }
306}
307static void logEvent(const std::string_view stateHandler, const Event event)
308{
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700309 std::string logMsg{stateHandler};
310 logMsg += ": " + getEventName(event) + " event received";
311 phosphor::logging::log<phosphor::logging::level::INFO>(
312 logMsg.c_str(),
313 phosphor::logging::entry("EVENT=%s", getEventName(event).c_str()));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700314}
315
316// Power state handlers
317static void powerStateOn(const Event event);
318static void powerStateWaitForPSPowerOK(const Event event);
319static void powerStateWaitForSIOPowerGood(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700320static void powerStateOff(const Event event);
321static void powerStateTransitionToOff(const Event event);
322static void powerStateGracefulTransitionToOff(const Event event);
323static void powerStateCycleOff(const Event event);
324static void powerStateTransitionToCycleOff(const Event event);
325static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700326static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700327
328static std::function<void(const Event)> getPowerStateHandler(PowerState state)
329{
330 switch (state)
331 {
332 case PowerState::on:
333 return powerStateOn;
334 break;
335 case PowerState::waitForPSPowerOK:
336 return powerStateWaitForPSPowerOK;
337 break;
338 case PowerState::waitForSIOPowerGood:
339 return powerStateWaitForSIOPowerGood;
340 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700341 case PowerState::off:
342 return powerStateOff;
343 break;
344 case PowerState::transitionToOff:
345 return powerStateTransitionToOff;
346 break;
347 case PowerState::gracefulTransitionToOff:
348 return powerStateGracefulTransitionToOff;
349 break;
350 case PowerState::cycleOff:
351 return powerStateCycleOff;
352 break;
353 case PowerState::transitionToCycleOff:
354 return powerStateTransitionToCycleOff;
355 break;
356 case PowerState::gracefulTransitionToCycleOff:
357 return powerStateGracefulTransitionToCycleOff;
358 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700359 case PowerState::checkForWarmReset:
360 return powerStateCheckForWarmReset;
361 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700362 default:
363 return std::function<void(const Event)>{};
364 break;
365 }
366};
367
368static void sendPowerControlEvent(const Event event)
369{
370 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
371 if (handler == nullptr)
372 {
373 std::cerr << "Failed to find handler for power state: "
374 << static_cast<int>(powerState) << "\n";
375 return;
376 }
377 handler(event);
378}
379
380static uint64_t getCurrentTimeMs()
381{
382 struct timespec time = {};
383
384 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
385 {
386 return 0;
387 }
388 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
389 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
390
391 return currentTimeMs;
392}
393
394static constexpr std::string_view getHostState(const PowerState state)
395{
396 switch (state)
397 {
398 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700399 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700400 case PowerState::gracefulTransitionToCycleOff:
401 return "xyz.openbmc_project.State.Host.HostState.Running";
402 break;
403 case PowerState::waitForPSPowerOK:
404 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700405 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700406 case PowerState::transitionToOff:
407 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700408 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700409 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700410 return "xyz.openbmc_project.State.Host.HostState.Off";
411 break;
412 default:
413 return "";
414 break;
415 }
416};
417static constexpr std::string_view getChassisState(const PowerState state)
418{
419 switch (state)
420 {
421 case PowerState::on:
422 case PowerState::transitionToOff:
423 case PowerState::gracefulTransitionToOff:
424 case PowerState::transitionToCycleOff:
425 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700426 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700427 return "xyz.openbmc_project.State.Chassis.PowerState.On";
428 break;
429 case PowerState::waitForPSPowerOK:
430 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700431 case PowerState::off:
432 case PowerState::cycleOff:
433 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
434 break;
435 default:
436 return "";
437 break;
438 }
439};
440static void savePowerState(const PowerState state)
441{
442 powerStateSaveTimer.expires_after(
443 std::chrono::milliseconds(powerOffSaveTimeMs));
444 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
445 if (ec)
446 {
447 // operation_aborted is expected if timer is canceled before
448 // completion.
449 if (ec != boost::asio::error::operation_aborted)
450 {
451 std::cerr << "Power-state save async_wait failed: "
452 << ec.message() << "\n";
453 }
454 return;
455 }
456 std::ofstream powerStateStream(powerControlDir / powerStateFile);
457 powerStateStream << getChassisState(state);
458 });
459}
460static void setPowerState(const PowerState state)
461{
462 powerState = state;
463 logStateTransition(state);
464
465 hostIface->set_property("CurrentHostState",
466 std::string(getHostState(powerState)));
467
468 chassisIface->set_property("CurrentPowerState",
469 std::string(getChassisState(powerState)));
470 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
471
472 // Save the power state for the restore policy
473 savePowerState(state);
474}
475
476enum class RestartCause
477{
478 command,
479 resetButton,
480 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700481 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700482 powerPolicyOn,
483 powerPolicyRestore,
484 softReset,
485};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700486static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700487static std::string getRestartCause(RestartCause cause)
488{
489 switch (cause)
490 {
491 case RestartCause::command:
492 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
493 break;
494 case RestartCause::resetButton:
495 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
496 break;
497 case RestartCause::powerButton:
498 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
499 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700500 case RestartCause::watchdog:
501 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
502 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700503 case RestartCause::powerPolicyOn:
504 return "xyz.openbmc_project.State.Host.RestartCause."
505 "PowerPolicyAlwaysOn";
506 break;
507 case RestartCause::powerPolicyRestore:
508 return "xyz.openbmc_project.State.Host.RestartCause."
509 "PowerPolicyPreviousState";
510 break;
511 case RestartCause::softReset:
512 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
513 break;
514 default:
515 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
516 break;
517 }
518}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700519static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700520{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700521 // Add this to the set of causes for this restart
522 causeSet.insert(cause);
523}
524static void clearRestartCause()
525{
526 // Clear the set for the next restart
527 causeSet.clear();
528}
529static void setRestartCauseProperty(const std::string& cause)
530{
531 std::cerr << "RestartCause set to " << cause << "\n";
532 restartCauseIface->set_property("RestartCause", cause);
533}
Rashmi RV89f61312020-01-22 15:41:50 +0530534
535static void resetACBootProperty()
536{
537 if ((causeSet.contains(RestartCause::command)) ||
538 (causeSet.contains(RestartCause::softReset)))
539 {
540 conn->async_method_call(
541 [](boost::system::error_code ec) {
542 if (ec)
543 {
544 std::cerr << "failed to reset ACBoot property\n";
545 }
546 },
547 "xyz.openbmc_project.Settings",
548 "/xyz/openbmc_project/control/host0/ac_boot",
549 "org.freedesktop.DBus.Properties", "Set",
550 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
551 std::variant<std::string>{"False"});
552 }
553}
554
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700555static void setRestartCause()
556{
557 // Determine the actual restart cause based on the set of causes
558 std::string restartCause =
559 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
560 if (causeSet.contains(RestartCause::watchdog))
561 {
562 restartCause = getRestartCause(RestartCause::watchdog);
563 }
564 else if (causeSet.contains(RestartCause::command))
565 {
566 restartCause = getRestartCause(RestartCause::command);
567 }
568 else if (causeSet.contains(RestartCause::resetButton))
569 {
570 restartCause = getRestartCause(RestartCause::resetButton);
571 }
572 else if (causeSet.contains(RestartCause::powerButton))
573 {
574 restartCause = getRestartCause(RestartCause::powerButton);
575 }
576 else if (causeSet.contains(RestartCause::powerPolicyOn))
577 {
578 restartCause = getRestartCause(RestartCause::powerPolicyOn);
579 }
580 else if (causeSet.contains(RestartCause::powerPolicyRestore))
581 {
582 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
583 }
584 else if (causeSet.contains(RestartCause::softReset))
585 {
586 restartCause = getRestartCause(RestartCause::softReset);
587 }
588
589 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700590}
591
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700592static void systemPowerGoodFailedLog()
593{
594 sd_journal_send(
595 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
596 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
597 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
598 sioPowerGoodWatchdogTimeMs, NULL);
599}
600
601static void psPowerOKFailedLog()
602{
603 sd_journal_send(
604 "MESSAGE=PowerControl: power supply power good failed to assert",
605 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
606 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
607 psPowerOKWatchdogTimeMs, NULL);
608}
609
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700610static void powerRestorePolicyLog()
611{
612 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
613 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
614 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
615}
616
617static void powerButtonPressLog()
618{
619 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
620 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
621 "OpenBMC.0.1.PowerButtonPressed", NULL);
622}
623
624static void resetButtonPressLog()
625{
626 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
627 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
628 "OpenBMC.0.1.ResetButtonPressed", NULL);
629}
630
631static void nmiButtonPressLog()
632{
633 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
634 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
635 "OpenBMC.0.1.NMIButtonPressed", NULL);
636}
637
638static void nmiDiagIntLog()
639{
640 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
641 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
642 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
643}
644
645static int initializePowerStateStorage()
646{
647 // create the power control directory if it doesn't exist
648 std::error_code ec;
649 if (!(std::filesystem::create_directories(powerControlDir, ec)))
650 {
651 if (ec.value() != 0)
652 {
653 std::cerr << "failed to create " << powerControlDir << ": "
654 << ec.message() << "\n";
655 return -1;
656 }
657 }
658 // Create the power state file if it doesn't exist
659 if (!std::filesystem::exists(powerControlDir / powerStateFile))
660 {
661 std::ofstream powerStateStream(powerControlDir / powerStateFile);
662 powerStateStream << getChassisState(powerState);
663 }
664 return 0;
665}
666
667static bool wasPowerDropped()
668{
669 std::ifstream powerStateStream(powerControlDir / powerStateFile);
670 if (!powerStateStream.is_open())
671 {
672 std::cerr << "Failed to open power state file\n";
673 return false;
674 }
675
676 std::string state;
677 std::getline(powerStateStream, state);
678 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
679}
680
681static void invokePowerRestorePolicy(const std::string& policy)
682{
683 // Async events may call this twice, but we only want to run once
684 static bool policyInvoked = false;
685 if (policyInvoked)
686 {
687 return;
688 }
689 policyInvoked = true;
690
691 std::cerr << "Power restore delay expired, invoking " << policy << "\n";
692 if (policy ==
693 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
694 {
695 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700696 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700697 }
698 else if (policy == "xyz.openbmc_project.Control.Power.RestorePolicy."
699 "Policy.Restore")
700 {
701 if (wasPowerDropped())
702 {
703 std::cerr << "Power was dropped, restoring Host On state\n";
704 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700705 setRestartCauseProperty(
706 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700707 }
708 else
709 {
710 std::cerr << "No power drop, restoring Host Off state\n";
711 }
712 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -0700713 // We're done with the previous power state for the restore policy, so store
714 // the current state
715 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700716}
717
718static void powerRestorePolicyDelay(int delay)
719{
720 // Async events may call this twice, but we only want to run once
721 static bool delayStarted = false;
722 if (delayStarted)
723 {
724 return;
725 }
726 delayStarted = true;
727 // Calculate the delay from now to meet the requested delay
728 // Subtract the approximate uboot time
729 static constexpr const int ubootSeconds = 20;
730 delay -= ubootSeconds;
731 // Subtract the time since boot
732 struct sysinfo info = {};
733 if (sysinfo(&info) == 0)
734 {
735 delay -= info.uptime;
736 }
737 // 0 is the minimum delay
738 delay = std::max(delay, 0);
739
740 static boost::asio::steady_timer powerRestorePolicyTimer(io);
741 powerRestorePolicyTimer.expires_after(std::chrono::seconds(delay));
742 std::cerr << "Power restore delay of " << delay << " seconds started\n";
743 powerRestorePolicyTimer.async_wait([](const boost::system::error_code ec) {
744 if (ec)
745 {
746 // operation_aborted is expected if timer is canceled before
747 // completion.
748 if (ec != boost::asio::error::operation_aborted)
749 {
750 std::cerr << "power restore policy async_wait failed: "
751 << ec.message() << "\n";
752 }
753 return;
754 }
755 // Get Power Restore Policy
756 // In case PowerRestorePolicy is not available, set a match for it
757 static std::unique_ptr<sdbusplus::bus::match::match>
758 powerRestorePolicyMatch = std::make_unique<
759 sdbusplus::bus::match::match>(
760 *conn,
761 "type='signal',interface='org.freedesktop.DBus.Properties',"
762 "member='PropertiesChanged',arg0namespace='xyz.openbmc_"
763 "project.Control.Power.RestorePolicy'",
764 [](sdbusplus::message::message& msg) {
765 std::string interfaceName;
766 boost::container::flat_map<std::string,
767 std::variant<std::string>>
768 propertiesChanged;
769 std::string policy;
770 try
771 {
772 msg.read(interfaceName, propertiesChanged);
773 policy = std::get<std::string>(
774 propertiesChanged.begin()->second);
775 }
776 catch (std::exception& e)
777 {
778 std::cerr
779 << "Unable to read power restore policy value\n";
780 powerRestorePolicyMatch.reset();
781 return;
782 }
783 invokePowerRestorePolicy(policy);
784 powerRestorePolicyMatch.reset();
785 });
786
787 // Check if it's already on DBus
788 conn->async_method_call(
789 [](boost::system::error_code ec,
790 const std::variant<std::string>& policyProperty) {
791 if (ec)
792 {
793 return;
794 }
795 powerRestorePolicyMatch.reset();
796 const std::string* policy =
797 std::get_if<std::string>(&policyProperty);
798 if (policy == nullptr)
799 {
800 std::cerr << "Unable to read power restore policy value\n";
801 return;
802 }
803 invokePowerRestorePolicy(*policy);
804 },
805 "xyz.openbmc_project.Settings",
806 "/xyz/openbmc_project/control/host0/power_restore_policy",
807 "org.freedesktop.DBus.Properties", "Get",
808 "xyz.openbmc_project.Control.Power.RestorePolicy",
809 "PowerRestorePolicy");
810 });
811}
812
813static void powerRestorePolicyStart()
814{
815 std::cerr << "Power restore policy started\n";
816 powerRestorePolicyLog();
817
818 // Get the desired delay time
819 // In case PowerRestoreDelay is not available, set a match for it
820 static std::unique_ptr<sdbusplus::bus::match::match>
821 powerRestoreDelayMatch = std::make_unique<sdbusplus::bus::match::match>(
822 *conn,
823 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
824 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Control."
825 "Power.RestoreDelay'",
826 [](sdbusplus::message::message& msg) {
827 std::string interfaceName;
828 boost::container::flat_map<std::string, std::variant<uint16_t>>
829 propertiesChanged;
830 int delay = 0;
831 try
832 {
833 msg.read(interfaceName, propertiesChanged);
834 delay =
835 std::get<uint16_t>(propertiesChanged.begin()->second);
836 }
837 catch (std::exception& e)
838 {
839 std::cerr << "Unable to read power restore delay value\n";
840 powerRestoreDelayMatch.reset();
841 return;
842 }
843 powerRestorePolicyDelay(delay);
844 powerRestoreDelayMatch.reset();
845 });
846
847 // Check if it's already on DBus
848 conn->async_method_call(
849 [](boost::system::error_code ec,
850 const std::variant<uint16_t>& delayProperty) {
851 if (ec)
852 {
853 return;
854 }
855 powerRestoreDelayMatch.reset();
856 const uint16_t* delay = std::get_if<uint16_t>(&delayProperty);
857 if (delay == nullptr)
858 {
859 std::cerr << "Unable to read power restore delay value\n";
860 return;
861 }
862 powerRestorePolicyDelay(*delay);
863 },
864 "xyz.openbmc_project.Settings",
865 "/xyz/openbmc_project/control/power_restore_delay",
866 "org.freedesktop.DBus.Properties", "Get",
867 "xyz.openbmc_project.Control.Power.RestoreDelay", "PowerRestoreDelay");
868}
869
870static void powerRestorePolicyCheck()
871{
872 // In case ACBoot is not available, set a match for it
873 static std::unique_ptr<sdbusplus::bus::match::match> acBootMatch =
874 std::make_unique<sdbusplus::bus::match::match>(
875 *conn,
876 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
877 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Common."
878 "ACBoot'",
879 [](sdbusplus::message::message& msg) {
880 std::string interfaceName;
881 boost::container::flat_map<std::string,
882 std::variant<std::string>>
883 propertiesChanged;
884 std::string acBoot;
885 try
886 {
887 msg.read(interfaceName, propertiesChanged);
888 acBoot = std::get<std::string>(
889 propertiesChanged.begin()->second);
890 }
891 catch (std::exception& e)
892 {
893 std::cerr << "Unable to read AC Boot status\n";
894 acBootMatch.reset();
895 return;
896 }
897 if (acBoot == "Unknown")
898 {
899 return;
900 }
901 if (acBoot == "True")
902 {
903 // Start the Power Restore policy
904 powerRestorePolicyStart();
905 }
906 acBootMatch.reset();
907 });
908
909 // Check if it's already on DBus
910 conn->async_method_call(
911 [](boost::system::error_code ec,
912 const std::variant<std::string>& acBootProperty) {
913 if (ec)
914 {
915 return;
916 }
917 const std::string* acBoot =
918 std::get_if<std::string>(&acBootProperty);
919 if (acBoot == nullptr)
920 {
921 std::cerr << "Unable to read AC Boot status\n";
922 return;
923 }
924 if (*acBoot == "Unknown")
925 {
926 return;
927 }
928 if (*acBoot == "True")
929 {
930 // Start the Power Restore policy
931 powerRestorePolicyStart();
932 }
933 acBootMatch.reset();
934 },
935 "xyz.openbmc_project.Settings",
936 "/xyz/openbmc_project/control/host0/ac_boot",
937 "org.freedesktop.DBus.Properties", "Get",
938 "xyz.openbmc_project.Common.ACBoot", "ACBoot");
939}
940
941static bool requestGPIOEvents(
942 const std::string& name, const std::function<void()>& handler,
943 gpiod::line& gpioLine,
944 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
945{
946 // Find the GPIO line
947 gpioLine = gpiod::find_line(name);
948 if (!gpioLine)
949 {
950 std::cerr << "Failed to find the " << name << " line\n";
951 return false;
952 }
953
954 try
955 {
956 gpioLine.request(
957 {"power-control", gpiod::line_request::EVENT_BOTH_EDGES});
958 }
959 catch (std::exception&)
960 {
961 std::cerr << "Failed to request events for " << name << "\n";
962 return false;
963 }
964
965 int gpioLineFd = gpioLine.event_get_fd();
966 if (gpioLineFd < 0)
967 {
968 std::cerr << "Failed to get " << name << " fd\n";
969 return false;
970 }
971
972 gpioEventDescriptor.assign(gpioLineFd);
973
974 gpioEventDescriptor.async_wait(
975 boost::asio::posix::stream_descriptor::wait_read,
976 [&name, handler](const boost::system::error_code ec) {
977 if (ec)
978 {
979 std::cerr << name << " fd handler error: " << ec.message()
980 << "\n";
981 // TODO: throw here to force power-control to restart?
982 return;
983 }
984 handler();
985 });
986 return true;
987}
988
989static bool setGPIOOutput(const std::string& name, const int value,
990 gpiod::line& gpioLine)
991{
992 // Find the GPIO line
993 gpioLine = gpiod::find_line(name);
994 if (!gpioLine)
995 {
996 std::cerr << "Failed to find the " << name << " line.\n";
997 return false;
998 }
999
1000 // Request GPIO output to specified value
1001 try
1002 {
1003 gpioLine.request({__FUNCTION__, gpiod::line_request::DIRECTION_OUTPUT},
1004 value);
1005 }
1006 catch (std::exception&)
1007 {
1008 std::cerr << "Failed to request " << name << " output\n";
1009 return false;
1010 }
1011
1012 std::cerr << name << " set to " << std::to_string(value) << "\n";
1013 return true;
1014}
1015
1016static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1017 const std::string& name, const int value,
1018 const int durationMs)
1019{
1020 // Set the masked GPIO line to the specified value
1021 maskedGPIOLine.set_value(value);
1022 std::cerr << name << " set to " << std::to_string(value) << "\n";
1023 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
1024 gpioAssertTimer.async_wait(
1025 [maskedGPIOLine, value, name](const boost::system::error_code ec) {
1026 // Set the masked GPIO line back to the opposite value
1027 maskedGPIOLine.set_value(!value);
1028 std::cerr << name << " released\n";
1029 if (ec)
1030 {
1031 // operation_aborted is expected if timer is canceled before
1032 // completion.
1033 if (ec != boost::asio::error::operation_aborted)
1034 {
1035 std::cerr << name << " async_wait failed: " + ec.message()
1036 << "\n";
1037 }
1038 }
1039 });
1040 return 0;
1041}
1042
1043static int setGPIOOutputForMs(const std::string& name, const int value,
1044 const int durationMs)
1045{
1046 // If the requested GPIO is masked, use the mask line to set the output
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001047 if (powerButtonMask && name == power_control::powerOutName)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001048 {
1049 return setMaskedGPIOOutputForMs(powerButtonMask, name, value,
1050 durationMs);
1051 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001052 if (resetButtonMask && name == power_control::resetOutName)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001053 {
1054 return setMaskedGPIOOutputForMs(resetButtonMask, name, value,
1055 durationMs);
1056 }
1057
1058 // No mask set, so request and set the GPIO normally
1059 gpiod::line gpioLine;
1060 if (!setGPIOOutput(name, value, gpioLine))
1061 {
1062 return -1;
1063 }
1064 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
1065 gpioAssertTimer.async_wait(
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001066 [gpioLine, value, name](const boost::system::error_code ec) {
1067 // Set the GPIO line back to the opposite value
1068 gpioLine.set_value(!value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001069 std::cerr << name << " released\n";
1070 if (ec)
1071 {
1072 // operation_aborted is expected if timer is canceled before
1073 // completion.
1074 if (ec != boost::asio::error::operation_aborted)
1075 {
1076 std::cerr << name << " async_wait failed: " << ec.message()
1077 << "\n";
1078 }
1079 }
1080 });
1081 return 0;
1082}
1083
1084static void powerOn()
1085{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001086 setGPIOOutputForMs(power_control::powerOutName, 0, powerPulseTimeMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001087}
1088
1089static void gracefulPowerOff()
1090{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001091 setGPIOOutputForMs(power_control::powerOutName, 0, powerPulseTimeMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001092}
1093
1094static void forcePowerOff()
1095{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001096 if (setGPIOOutputForMs(power_control::powerOutName, 0,
1097 forceOffPulseTimeMs) < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001098 {
1099 return;
1100 }
1101
1102 // If the force off timer expires, then the PCH power-button override
1103 // failed, so attempt the Unconditional Powerdown SMBus command.
1104 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1105 if (ec)
1106 {
1107 // operation_aborted is expected if timer is canceled before
1108 // completion.
1109 if (ec != boost::asio::error::operation_aborted)
1110 {
1111 std::cerr << "Force power off async_wait failed: "
1112 << ec.message() << "\n";
1113 }
1114 return;
1115 }
1116 std::cerr << "PCH Power-button override failed. Issuing Unconditional "
1117 "Powerdown SMBus command.\n";
1118 const static constexpr size_t pchDevBusAddress = 3;
1119 const static constexpr size_t pchDevSlaveAddress = 0x44;
1120 const static constexpr size_t pchCmdReg = 0;
1121 const static constexpr size_t pchPowerDownCmd = 0x02;
1122 if (i2cSet(pchDevBusAddress, pchDevSlaveAddress, pchCmdReg,
1123 pchPowerDownCmd) < 0)
1124 {
1125 std::cerr << "Unconditional Powerdown command failed! Not sure "
1126 "what to do now.\n";
1127 }
1128 });
1129}
1130
1131static void reset()
1132{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001133 setGPIOOutputForMs(power_control::resetOutName, 0, resetPulseTimeMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001134}
1135
1136static void gracefulPowerOffTimerStart()
1137{
1138 std::cerr << "Graceful power-off timer started\n";
1139 gracefulPowerOffTimer.expires_after(
1140 std::chrono::milliseconds(gracefulPowerOffTimeMs));
1141 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1142 if (ec)
1143 {
1144 // operation_aborted is expected if timer is canceled before
1145 // completion.
1146 if (ec != boost::asio::error::operation_aborted)
1147 {
1148 std::cerr << "Graceful power-off async_wait failed: "
1149 << ec.message() << "\n";
1150 }
1151 std::cerr << "Graceful power-off timer canceled\n";
1152 return;
1153 }
1154 std::cerr << "Graceful power-off timer completed\n";
1155 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1156 });
1157}
1158
1159static void powerCycleTimerStart()
1160{
1161 std::cerr << "Power-cycle timer started\n";
1162 powerCycleTimer.expires_after(std::chrono::milliseconds(powerCycleTimeMs));
1163 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1164 if (ec)
1165 {
1166 // operation_aborted is expected if timer is canceled before
1167 // completion.
1168 if (ec != boost::asio::error::operation_aborted)
1169 {
1170 std::cerr << "Power-cycle async_wait failed: " << ec.message()
1171 << "\n";
1172 }
1173 std::cerr << "Power-cycle timer canceled\n";
1174 return;
1175 }
1176 std::cerr << "Power-cycle timer completed\n";
1177 sendPowerControlEvent(Event::powerCycleTimerExpired);
1178 });
1179}
1180
1181static void psPowerOKWatchdogTimerStart()
1182{
1183 std::cerr << "power supply power OK watchdog timer started\n";
1184 psPowerOKWatchdogTimer.expires_after(
1185 std::chrono::milliseconds(psPowerOKWatchdogTimeMs));
1186 psPowerOKWatchdogTimer.async_wait(
1187 [](const boost::system::error_code ec) {
1188 if (ec)
1189 {
1190 // operation_aborted is expected if timer is canceled before
1191 // completion.
1192 if (ec != boost::asio::error::operation_aborted)
1193 {
1194 std::cerr
1195 << "power supply power OK watchdog async_wait failed: "
1196 << ec.message() << "\n";
1197 }
1198 std::cerr << "power supply power OK watchdog timer canceled\n";
1199 return;
1200 }
1201 std::cerr << "power supply power OK watchdog timer expired\n";
1202 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1203 });
1204}
1205
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001206static void warmResetCheckTimerStart()
1207{
1208 std::cerr << "Warm reset check timer started\n";
1209 warmResetCheckTimer.expires_after(
1210 std::chrono::milliseconds(warmResetCheckTimeMs));
1211 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1212 if (ec)
1213 {
1214 // operation_aborted is expected if timer is canceled before
1215 // completion.
1216 if (ec != boost::asio::error::operation_aborted)
1217 {
1218 std::cerr << "Warm reset check async_wait failed: "
1219 << ec.message() << "\n";
1220 }
1221 std::cerr << "Warm reset check timer canceled\n";
1222 return;
1223 }
1224 std::cerr << "Warm reset check timer completed\n";
1225 sendPowerControlEvent(Event::warmResetDetected);
1226 });
1227}
1228
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001229static void pohCounterTimerStart()
1230{
1231 std::cerr << "POH timer started\n";
1232 // Set the time-out as 1 hour, to align with POH command in ipmid
1233 pohCounterTimer.expires_after(std::chrono::hours(1));
1234 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1235 if (ec)
1236 {
1237 // operation_aborted is expected if timer is canceled before
1238 // completion.
1239 if (ec != boost::asio::error::operation_aborted)
1240 {
1241 std::cerr << "POH timer async_wait failed: " << ec.message()
1242 << "\n";
1243 }
1244 std::cerr << "POH timer canceled\n";
1245 return;
1246 }
1247
1248 if (getHostState(powerState) !=
1249 "xyz.openbmc_project.State.Host.HostState.Running")
1250 {
1251 return;
1252 }
1253
1254 conn->async_method_call(
1255 [](boost::system::error_code ec,
1256 const std::variant<uint32_t>& pohCounterProperty) {
1257 if (ec)
1258 {
1259 std::cerr << "error to get poh counter\n";
1260 return;
1261 }
1262 const uint32_t* pohCounter =
1263 std::get_if<uint32_t>(&pohCounterProperty);
1264 if (pohCounter == nullptr)
1265 {
1266 std::cerr << "unable to read poh counter\n";
1267 return;
1268 }
1269
1270 conn->async_method_call(
1271 [](boost::system::error_code ec) {
1272 if (ec)
1273 {
1274 std::cerr << "failed to set poh counter\n";
1275 }
1276 },
1277 "xyz.openbmc_project.Settings",
1278 "/xyz/openbmc_project/state/chassis0",
1279 "org.freedesktop.DBus.Properties", "Set",
1280 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1281 std::variant<uint32_t>(*pohCounter + 1));
1282 },
1283 "xyz.openbmc_project.Settings",
1284 "/xyz/openbmc_project/state/chassis0",
1285 "org.freedesktop.DBus.Properties", "Get",
1286 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1287
1288 pohCounterTimerStart();
1289 });
1290}
1291
1292static void currentHostStateMonitor()
1293{
Yong Li8d660212019-12-27 10:18:10 +08001294 if (getHostState(powerState) ==
1295 "xyz.openbmc_project.State.Host.HostState.Running")
1296 {
1297 pohCounterTimerStart();
1298 // Clear the restart cause set for the next restart
1299 clearRestartCause();
1300 }
1301 else
1302 {
1303 pohCounterTimer.cancel();
1304 // Set the restart cause set for this restart
1305 setRestartCause();
1306 }
1307
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001308 static auto match = sdbusplus::bus::match::match(
1309 *conn,
1310 "type='signal',member='PropertiesChanged', "
1311 "interface='org.freedesktop.DBus.Properties', "
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001312 "arg0='xyz.openbmc_project.State.Host'",
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001313 [](sdbusplus::message::message& message) {
1314 std::string intfName;
1315 std::map<std::string, std::variant<std::string>> properties;
1316
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001317 try
1318 {
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001319 message.read(intfName, properties);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001320 }
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001321 catch (std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001322 {
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001323 std::cerr << "Unable to read host state\n";
1324 return;
1325 }
1326 if (properties.empty())
1327 {
1328 std::cerr << "ERROR: Empty PropertiesChanged signal received\n";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001329 return;
1330 }
1331
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001332 // We only want to check for CurrentHostState
1333 if (properties.begin()->first != "CurrentHostState")
1334 {
1335 return;
1336 }
1337 std::string* currentHostState =
1338 std::get_if<std::string>(&(properties.begin()->second));
1339 if (currentHostState == nullptr)
1340 {
1341 std::cerr << properties.begin()->first << " property invalid\n";
1342 return;
1343 }
1344
1345 if (*currentHostState ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001346 "xyz.openbmc_project.State.Host.HostState.Running")
1347 {
1348 pohCounterTimerStart();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001349 // Clear the restart cause set for the next restart
1350 clearRestartCause();
Yong Li8d660212019-12-27 10:18:10 +08001351 sd_journal_send("MESSAGE=Host system DC power is on",
1352 "PRIORITY=%i", LOG_INFO,
1353 "REDFISH_MESSAGE_ID=%s",
1354 "OpenBMC.0.1.DCPowerOn", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001355 }
1356 else
1357 {
1358 pohCounterTimer.cancel();
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301359 // POST_COMPLETE GPIO event is not working in some platforms
1360 // when power state is changed to OFF. This resulted in
1361 // 'OperatingSystemState' to stay at 'Standby', even though
1362 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1363 // if HostState is trurned to OFF.
1364 osIface->set_property("OperatingSystemState",
1365 std::string("Inactive"));
1366
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001367 // Set the restart cause set for this restart
1368 setRestartCause();
Rashmi RV89f61312020-01-22 15:41:50 +05301369 resetACBootProperty();
Yong Li8d660212019-12-27 10:18:10 +08001370 sd_journal_send("MESSAGE=Host system DC power is off",
1371 "PRIORITY=%i", LOG_INFO,
1372 "REDFISH_MESSAGE_ID=%s",
1373 "OpenBMC.0.1.DCPowerOff", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001374 }
1375 });
1376}
1377
1378static void sioPowerGoodWatchdogTimerStart()
1379{
1380 std::cerr << "SIO power good watchdog timer started\n";
1381 sioPowerGoodWatchdogTimer.expires_after(
1382 std::chrono::milliseconds(sioPowerGoodWatchdogTimeMs));
1383 sioPowerGoodWatchdogTimer.async_wait(
1384 [](const boost::system::error_code ec) {
1385 if (ec)
1386 {
1387 // operation_aborted is expected if timer is canceled before
1388 // completion.
1389 if (ec != boost::asio::error::operation_aborted)
1390 {
1391 std::cerr << "SIO power good watchdog async_wait failed: "
1392 << ec.message() << "\n";
1393 }
1394 std::cerr << "SIO power good watchdog timer canceled\n";
1395 return;
1396 }
1397 std::cerr << "SIO power good watchdog timer completed\n";
1398 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1399 });
1400}
1401
1402static void powerStateOn(const Event event)
1403{
1404 logEvent(__FUNCTION__, event);
1405 switch (event)
1406 {
1407 case Event::psPowerOKDeAssert:
1408 setPowerState(PowerState::off);
1409 // DC power is unexpectedly lost, beep
1410 beep(beepPowerFail);
1411 break;
1412 case Event::sioS5Assert:
1413 setPowerState(PowerState::transitionToOff);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001414 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001415 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001416 case Event::postCompleteDeAssert:
1417 setPowerState(PowerState::checkForWarmReset);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001418 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001419 warmResetCheckTimerStart();
1420 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001421 case Event::powerButtonPressed:
1422 setPowerState(PowerState::gracefulTransitionToOff);
1423 gracefulPowerOffTimerStart();
1424 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001425 case Event::resetButtonPressed:
1426 setPowerState(PowerState::checkForWarmReset);
1427 warmResetCheckTimerStart();
1428 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001429 case Event::powerOffRequest:
1430 setPowerState(PowerState::transitionToOff);
1431 forcePowerOff();
1432 break;
1433 case Event::gracefulPowerOffRequest:
1434 setPowerState(PowerState::gracefulTransitionToOff);
1435 gracefulPowerOffTimerStart();
1436 gracefulPowerOff();
1437 break;
1438 case Event::powerCycleRequest:
1439 setPowerState(PowerState::transitionToCycleOff);
1440 forcePowerOff();
1441 break;
1442 case Event::gracefulPowerCycleRequest:
1443 setPowerState(PowerState::gracefulTransitionToCycleOff);
1444 gracefulPowerOffTimerStart();
1445 gracefulPowerOff();
1446 break;
1447 case Event::resetRequest:
1448 reset();
1449 break;
1450 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001451 phosphor::logging::log<phosphor::logging::level::INFO>(
1452 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001453 break;
1454 }
1455}
1456
1457static void powerStateWaitForPSPowerOK(const Event event)
1458{
1459 logEvent(__FUNCTION__, event);
1460 switch (event)
1461 {
1462 case Event::psPowerOKAssert:
1463 // Cancel any GPIO assertions held during the transition
1464 gpioAssertTimer.cancel();
1465 psPowerOKWatchdogTimer.cancel();
1466 sioPowerGoodWatchdogTimerStart();
1467 setPowerState(PowerState::waitForSIOPowerGood);
1468 break;
1469 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001470 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001471 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001472 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001473 case Event::sioPowerGoodAssert:
1474 psPowerOKWatchdogTimer.cancel();
1475 setPowerState(PowerState::on);
1476 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001477 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001478 phosphor::logging::log<phosphor::logging::level::INFO>(
1479 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001480 break;
1481 }
1482}
1483
1484static void powerStateWaitForSIOPowerGood(const Event event)
1485{
1486 logEvent(__FUNCTION__, event);
1487 switch (event)
1488 {
1489 case Event::sioPowerGoodAssert:
1490 sioPowerGoodWatchdogTimer.cancel();
1491 setPowerState(PowerState::on);
1492 break;
1493 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001494 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001495 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001496 break;
1497 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001498 phosphor::logging::log<phosphor::logging::level::INFO>(
1499 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001500 break;
1501 }
1502}
1503
1504static void powerStateOff(const Event event)
1505{
1506 logEvent(__FUNCTION__, event);
1507 switch (event)
1508 {
1509 case Event::psPowerOKAssert:
1510 setPowerState(PowerState::waitForSIOPowerGood);
1511 break;
1512 case Event::sioS5DeAssert:
1513 setPowerState(PowerState::waitForPSPowerOK);
1514 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001515 case Event::sioPowerGoodAssert:
1516 setPowerState(PowerState::on);
1517 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001518 case Event::powerButtonPressed:
1519 psPowerOKWatchdogTimerStart();
1520 setPowerState(PowerState::waitForPSPowerOK);
1521 break;
1522 case Event::powerOnRequest:
1523 psPowerOKWatchdogTimerStart();
1524 setPowerState(PowerState::waitForPSPowerOK);
1525 powerOn();
1526 break;
1527 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001528 phosphor::logging::log<phosphor::logging::level::INFO>(
1529 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001530 break;
1531 }
1532}
1533
1534static void powerStateTransitionToOff(const Event event)
1535{
1536 logEvent(__FUNCTION__, event);
1537 switch (event)
1538 {
1539 case Event::psPowerOKDeAssert:
1540 // Cancel any GPIO assertions held during the transition
1541 gpioAssertTimer.cancel();
1542 setPowerState(PowerState::off);
1543 break;
1544 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001545 phosphor::logging::log<phosphor::logging::level::INFO>(
1546 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001547 break;
1548 }
1549}
1550
1551static void powerStateGracefulTransitionToOff(const Event event)
1552{
1553 logEvent(__FUNCTION__, event);
1554 switch (event)
1555 {
1556 case Event::psPowerOKDeAssert:
1557 gracefulPowerOffTimer.cancel();
1558 setPowerState(PowerState::off);
1559 break;
1560 case Event::gracefulPowerOffTimerExpired:
1561 setPowerState(PowerState::on);
1562 break;
1563 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001564 phosphor::logging::log<phosphor::logging::level::INFO>(
1565 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001566 break;
1567 }
1568}
1569
1570static void powerStateCycleOff(const Event event)
1571{
1572 logEvent(__FUNCTION__, event);
1573 switch (event)
1574 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001575 case Event::psPowerOKAssert:
1576 powerCycleTimer.cancel();
1577 setPowerState(PowerState::waitForSIOPowerGood);
1578 break;
1579 case Event::sioS5DeAssert:
1580 powerCycleTimer.cancel();
1581 setPowerState(PowerState::waitForPSPowerOK);
1582 break;
1583 case Event::powerButtonPressed:
1584 powerCycleTimer.cancel();
1585 psPowerOKWatchdogTimerStart();
1586 setPowerState(PowerState::waitForPSPowerOK);
1587 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001588 case Event::powerCycleTimerExpired:
1589 psPowerOKWatchdogTimerStart();
1590 setPowerState(PowerState::waitForPSPowerOK);
1591 powerOn();
1592 break;
1593 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001594 phosphor::logging::log<phosphor::logging::level::INFO>(
1595 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001596 break;
1597 }
1598}
1599
1600static void powerStateTransitionToCycleOff(const Event event)
1601{
1602 logEvent(__FUNCTION__, event);
1603 switch (event)
1604 {
1605 case Event::psPowerOKDeAssert:
1606 // Cancel any GPIO assertions held during the transition
1607 gpioAssertTimer.cancel();
1608 setPowerState(PowerState::cycleOff);
1609 powerCycleTimerStart();
1610 break;
1611 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001612 phosphor::logging::log<phosphor::logging::level::INFO>(
1613 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001614 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:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001632 phosphor::logging::log<phosphor::logging::level::INFO>(
1633 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001634 break;
1635 }
1636}
1637
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001638static void powerStateCheckForWarmReset(const Event event)
1639{
1640 logEvent(__FUNCTION__, event);
1641 switch (event)
1642 {
1643 case Event::sioS5Assert:
1644 warmResetCheckTimer.cancel();
1645 setPowerState(PowerState::transitionToOff);
1646 break;
1647 case Event::warmResetDetected:
1648 setPowerState(PowerState::on);
1649 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001650 case Event::psPowerOKDeAssert:
1651 warmResetCheckTimer.cancel();
1652 setPowerState(PowerState::off);
1653 // DC power is unexpectedly lost, beep
1654 beep(beepPowerFail);
1655 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001656 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001657 phosphor::logging::log<phosphor::logging::level::INFO>(
1658 "No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001659 break;
1660 }
1661}
1662
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001663static void psPowerOKHandler()
1664{
1665 gpiod::line_event gpioLineEvent = psPowerOKLine.event_read();
1666
1667 Event powerControlEvent =
1668 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
1669 ? Event::psPowerOKAssert
1670 : Event::psPowerOKDeAssert;
1671
1672 sendPowerControlEvent(powerControlEvent);
1673 psPowerOKEvent.async_wait(
1674 boost::asio::posix::stream_descriptor::wait_read,
1675 [](const boost::system::error_code ec) {
1676 if (ec)
1677 {
1678 std::cerr << "power supply power OK handler error: "
1679 << ec.message() << "\n";
1680 return;
1681 }
1682 psPowerOKHandler();
1683 });
1684}
1685
1686static void sioPowerGoodHandler()
1687{
1688 gpiod::line_event gpioLineEvent = sioPowerGoodLine.event_read();
1689
1690 Event powerControlEvent =
1691 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
1692 ? Event::sioPowerGoodAssert
1693 : Event::sioPowerGoodDeAssert;
1694
1695 sendPowerControlEvent(powerControlEvent);
1696 sioPowerGoodEvent.async_wait(
1697 boost::asio::posix::stream_descriptor::wait_read,
1698 [](const boost::system::error_code ec) {
1699 if (ec)
1700 {
1701 std::cerr << "SIO power good handler error: " << ec.message()
1702 << "\n";
1703 return;
1704 }
1705 sioPowerGoodHandler();
1706 });
1707}
1708
1709static void sioOnControlHandler()
1710{
1711 gpiod::line_event gpioLineEvent = sioOnControlLine.event_read();
1712
1713 bool sioOnControl =
1714 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE;
1715 std::cerr << "SIO_ONCONTROL value changed: " << sioOnControl << "\n";
1716 sioOnControlEvent.async_wait(
1717 boost::asio::posix::stream_descriptor::wait_read,
1718 [](const boost::system::error_code ec) {
1719 if (ec)
1720 {
1721 std::cerr << "SIO ONCONTROL handler error: " << ec.message()
1722 << "\n";
1723 return;
1724 }
1725 sioOnControlHandler();
1726 });
1727}
1728
1729static void sioS5Handler()
1730{
1731 gpiod::line_event gpioLineEvent = sioS5Line.event_read();
1732
1733 Event powerControlEvent =
1734 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE
1735 ? Event::sioS5Assert
1736 : Event::sioS5DeAssert;
1737
1738 sendPowerControlEvent(powerControlEvent);
1739 sioS5Event.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1740 [](const boost::system::error_code ec) {
1741 if (ec)
1742 {
1743 std::cerr << "SIO S5 handler error: "
1744 << ec.message() << "\n";
1745 return;
1746 }
1747 sioS5Handler();
1748 });
1749}
1750
1751static void powerButtonHandler()
1752{
1753 gpiod::line_event gpioLineEvent = powerButtonLine.event_read();
1754
1755 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1756 {
1757 powerButtonPressLog();
1758 powerButtonIface->set_property("ButtonPressed", true);
1759 if (!powerButtonMask)
1760 {
1761 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001762 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001763 }
1764 else
1765 {
1766 std::cerr << "power button press masked\n";
1767 }
1768 }
1769 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
1770 {
1771 powerButtonIface->set_property("ButtonPressed", false);
1772 }
1773 powerButtonEvent.async_wait(
1774 boost::asio::posix::stream_descriptor::wait_read,
1775 [](const boost::system::error_code ec) {
1776 if (ec)
1777 {
1778 std::cerr << "power button handler error: " << ec.message()
1779 << "\n";
1780 return;
1781 }
1782 powerButtonHandler();
1783 });
1784}
1785
1786static void resetButtonHandler()
1787{
1788 gpiod::line_event gpioLineEvent = resetButtonLine.event_read();
1789
1790 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1791 {
1792 resetButtonPressLog();
1793 resetButtonIface->set_property("ButtonPressed", true);
1794 if (!resetButtonMask)
1795 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001796 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001797 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001798 }
1799 else
1800 {
1801 std::cerr << "reset button press masked\n";
1802 }
1803 }
1804 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
1805 {
1806 resetButtonIface->set_property("ButtonPressed", false);
1807 }
1808 resetButtonEvent.async_wait(
1809 boost::asio::posix::stream_descriptor::wait_read,
1810 [](const boost::system::error_code ec) {
1811 if (ec)
1812 {
1813 std::cerr << "reset button handler error: " << ec.message()
1814 << "\n";
1815 return;
1816 }
1817 resetButtonHandler();
1818 });
1819}
1820
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07001821static constexpr auto systemdBusname = "org.freedesktop.systemd1";
1822static constexpr auto systemdPath = "/org/freedesktop/systemd1";
1823static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
1824static constexpr auto systemTargetName = "chassis-system-reset.target";
1825
1826void systemReset()
1827{
1828 conn->async_method_call(
1829 [](boost::system::error_code ec) {
1830 if (ec)
1831 {
1832 phosphor::logging::log<phosphor::logging::level::ERR>(
1833 "Failed to call chassis system reset",
1834 phosphor::logging::entry("ERR=%s", ec.message().c_str()));
1835 }
1836 },
1837 systemdBusname, systemdPath, systemdInterface, "StartUnit",
1838 systemTargetName, "replace");
1839}
1840
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001841static void nmiSetEnablePorperty(bool value)
1842{
1843 conn->async_method_call(
1844 [](boost::system::error_code ec) {
1845 if (ec)
1846 {
1847 std::cerr << "failed to set NMI source\n";
1848 }
1849 },
Chen Yugang303bd582019-11-01 08:45:06 +08001850 "xyz.openbmc_project.Settings",
1851 "/xyz/openbmc_project/Chassis/Control/NMISource",
1852 "org.freedesktop.DBus.Properties", "Set",
1853 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
1854 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001855}
1856
1857static void nmiReset(void)
1858{
1859 static constexpr const uint8_t value = 1;
1860 const static constexpr int nmiOutPulseTimeMs = 200;
1861
1862 std::cerr << "NMI out action \n";
1863 nmiOutLine.set_value(value);
1864 std::cerr << nmiOutName << " set to " << std::to_string(value) << "\n";
1865 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
1866 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1867 // restore the NMI_OUT GPIO line back to the opposite value
1868 nmiOutLine.set_value(!value);
1869 std::cerr << nmiOutName << " released\n";
1870 if (ec)
1871 {
1872 // operation_aborted is expected if timer is canceled before
1873 // completion.
1874 if (ec != boost::asio::error::operation_aborted)
1875 {
1876 std::cerr << nmiOutName << " async_wait failed: " + ec.message()
1877 << "\n";
1878 }
1879 }
1880 });
1881 // log to redfish
1882 nmiDiagIntLog();
1883 std::cerr << "NMI out action completed\n";
1884 // reset Enable Property
1885 nmiSetEnablePorperty(false);
1886}
1887
1888static void nmiSourcePropertyMonitor(void)
1889{
1890 std::cerr << " NMI Source Property Monitor \n";
1891
1892 static std::unique_ptr<sdbusplus::bus::match::match> nmiSourceMatch =
1893 std::make_unique<sdbusplus::bus::match::match>(
1894 *conn,
1895 "type='signal',interface='org.freedesktop.DBus.Properties',"
Chen Yugang303bd582019-11-01 08:45:06 +08001896 "member='PropertiesChanged',arg0namespace='xyz.openbmc_project."
1897 "Chassis.Control."
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001898 "NMISource'",
1899 [](sdbusplus::message::message& msg) {
1900 std::string interfaceName;
1901 boost::container::flat_map<std::string,
1902 std::variant<bool, std::string>>
1903 propertiesChanged;
1904 std::string state;
1905 bool value = true;
1906 try
1907 {
1908 msg.read(interfaceName, propertiesChanged);
1909 if (propertiesChanged.begin()->first == "Enabled")
1910 {
1911 value =
1912 std::get<bool>(propertiesChanged.begin()->second);
1913 std::cerr
1914 << " NMI Enabled propertiesChanged value: " << value
1915 << "\n";
1916 nmiEnabled = value;
1917 if (nmiEnabled)
1918 {
1919 nmiReset();
1920 }
1921 }
1922 }
1923 catch (std::exception& e)
1924 {
1925 std::cerr << "Unable to read NMI source\n";
1926 return;
1927 }
1928 });
1929}
1930
1931static void setNmiSource()
1932{
1933 conn->async_method_call(
1934 [](boost::system::error_code ec) {
1935 if (ec)
1936 {
1937 std::cerr << "failed to set NMI source\n";
1938 }
1939 },
Chen Yugang303bd582019-11-01 08:45:06 +08001940 "xyz.openbmc_project.Settings",
1941 "/xyz/openbmc_project/Chassis/Control/NMISource",
1942 "org.freedesktop.DBus.Properties", "Set",
1943 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
1944 std::variant<std::string>{"xyz.openbmc_project.Chassis.Control."
1945 "NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001946 // set Enable Property
1947 nmiSetEnablePorperty(true);
1948}
1949
1950static void nmiButtonHandler()
1951{
1952 gpiod::line_event gpioLineEvent = nmiButtonLine.event_read();
1953
1954 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1955 {
1956 nmiButtonPressLog();
1957 nmiButtonIface->set_property("ButtonPressed", true);
1958 if (nmiButtonMasked)
1959 {
1960 std::cerr << "NMI button press masked\n";
1961 }
1962 else
1963 {
1964 setNmiSource();
1965 }
1966 }
1967 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
1968 {
1969 nmiButtonIface->set_property("ButtonPressed", false);
1970 }
1971 nmiButtonEvent.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1972 [](const boost::system::error_code ec) {
1973 if (ec)
1974 {
1975 std::cerr << "NMI button handler error: "
1976 << ec.message() << "\n";
1977 return;
1978 }
1979 nmiButtonHandler();
1980 });
1981}
1982
1983static void idButtonHandler()
1984{
1985 gpiod::line_event gpioLineEvent = idButtonLine.event_read();
1986
1987 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1988 {
1989 idButtonIface->set_property("ButtonPressed", true);
1990 }
1991 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
1992 {
1993 idButtonIface->set_property("ButtonPressed", false);
1994 }
1995 idButtonEvent.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1996 [](const boost::system::error_code& ec) {
1997 if (ec)
1998 {
1999 std::cerr << "ID button handler error: "
2000 << ec.message() << "\n";
2001 return;
2002 }
2003 idButtonHandler();
2004 });
2005}
2006
2007static void postCompleteHandler()
2008{
2009 gpiod::line_event gpioLineEvent = postCompleteLine.event_read();
2010
2011 bool postComplete =
2012 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002013 if (postComplete)
2014 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002015 sendPowerControlEvent(Event::postCompleteAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002016 osIface->set_property("OperatingSystemState", std::string("Standby"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002017 }
2018 else
2019 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002020 sendPowerControlEvent(Event::postCompleteDeAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002021 osIface->set_property("OperatingSystemState", std::string("Inactive"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002022 }
2023 postCompleteEvent.async_wait(
2024 boost::asio::posix::stream_descriptor::wait_read,
2025 [](const boost::system::error_code ec) {
2026 if (ec)
2027 {
2028 std::cerr << "POST complete handler error: " << ec.message()
2029 << "\n";
2030 return;
2031 }
2032 postCompleteHandler();
2033 });
2034}
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302035
2036static int loadConfigValues()
2037{
2038 const std::string configFilePath =
2039 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2040 ".json";
2041 std::ifstream configFile(configFilePath.c_str());
2042 if (!configFile.is_open())
2043 {
2044 std::cerr << "loadConfigValues : Cannot open config path\n ";
2045 return -1;
2046 }
2047 auto data = nlohmann::json::parse(configFile, nullptr);
2048
2049 if (data.is_discarded())
2050 {
2051 std::cerr << "Power config readings JSON parser failure";
2052 return -1;
2053 }
2054
2055 if (data.contains("IdButton"))
2056 {
2057 idButtonName = data["IdButton"];
2058 }
2059
2060 if (data.contains("NMIButton"))
2061 {
2062 nmiButtonName = data["NMIButton"];
2063 }
2064
2065 if (data.contains("NMIOut"))
2066 {
2067 nmiOutName = data["NMIOut"];
2068 }
2069
2070 if (data.contains("PostComplete"))
2071 {
2072 postCompleteName = data["PostComplete"];
2073 }
2074
2075 if (data.contains("PwrButton"))
2076 {
2077 powerButtonName = data["PwrButton"];
2078 }
2079
2080 if (data.contains("PwrOK"))
2081 {
2082 powerOkName = data["PwrOK"];
2083 }
2084
2085 if (data.contains("PwrOut"))
2086 {
2087 powerOutName = data["PwrOut"];
2088 }
2089
2090 if (data.contains("RstButton"))
2091 {
2092 resetButtonName = data["RstButton"];
2093 }
2094
2095 if (data.contains("RstOut"))
2096 {
2097 resetOutName = data["RstOut"];
2098 }
2099
2100 if (data.contains("SIOOnCtl"))
2101 {
2102 sioOnControlName = data["SIOOnCtl"];
2103 }
2104
2105 if (data.contains("SIOPwrGd"))
2106 {
2107 sioPwrGoodName = data["SIOPwrGd"];
2108 }
2109
2110 if (data.contains("SIOS5"))
2111 {
2112 sioS5Name = data["SIOS5"];
2113 }
2114
2115 return 0;
2116}
2117
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002118} // namespace power_control
2119
2120int main(int argc, char* argv[])
2121{
2122 std::cerr << "Start Chassis power control service...\n";
2123 power_control::conn =
2124 std::make_shared<sdbusplus::asio::connection>(power_control::io);
2125
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302126 // Load GPIO's through json config file
2127 if (power_control::loadConfigValues() == -1)
2128 {
2129 std::cerr << "Host" << power_control::node << ": "
2130 << "Error in Parsing...\n";
2131 }
2132
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002133 // Request all the dbus names
2134 power_control::conn->request_name("xyz.openbmc_project.State.Host");
2135 power_control::conn->request_name("xyz.openbmc_project.State.Chassis");
2136 power_control::conn->request_name(
2137 "xyz.openbmc_project.State.OperatingSystem");
2138 power_control::conn->request_name("xyz.openbmc_project.Chassis.Buttons");
Chen Yugang174ec662019-08-19 19:58:49 +08002139 power_control::conn->request_name("xyz.openbmc_project.Control.Host.NMI");
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002140 power_control::conn->request_name(
2141 "xyz.openbmc_project.Control.Host.RestartCause");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002142
2143 // Request PS_PWROK GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302144 if (!power_control::powerOkName.empty())
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002145 {
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302146 if (!power_control::requestGPIOEvents(
2147 power_control::powerOkName, power_control::psPowerOKHandler,
2148 power_control::psPowerOKLine, power_control::psPowerOKEvent))
2149 {
2150 return -1;
2151 }
2152 }
2153 else
2154 {
2155 std::cerr
2156 << "PowerOk name should be configured from json config file\n";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002157 return -1;
2158 }
2159
2160 // Request SIO_POWER_GOOD GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302161 if (!power_control::sioPwrGoodName.empty())
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002162 {
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302163 if (!power_control::requestGPIOEvents(
2164 power_control::sioPwrGoodName,
2165 power_control::sioPowerGoodHandler,
2166 power_control::sioPowerGoodLine,
2167 power_control::sioPowerGoodEvent))
2168 {
2169 return -1;
2170 }
2171 }
2172 else
2173 {
2174 std::cerr
2175 << "sioPwrGood name should be configured from json config file\n";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002176 return -1;
2177 }
2178
2179 // Request SIO_ONCONTROL GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302180 if (!power_control::sioOnControlName.empty())
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002181 {
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302182 if (!power_control::requestGPIOEvents(
2183 power_control::sioOnControlName,
2184 power_control::sioOnControlHandler,
2185 power_control::sioOnControlLine,
2186 power_control::sioOnControlEvent))
2187 {
2188 return -1;
2189 }
2190 }
2191 else
2192 {
2193 std::cerr
2194 << "sioOnControl name should be configured from json config file\n";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002195 return -1;
2196 }
2197
2198 // Request SIO_S5 GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302199 if (!power_control::sioS5Name.empty())
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002200 {
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302201 if (!power_control::requestGPIOEvents(
2202 power_control::sioS5Name, power_control::sioS5Handler,
2203 power_control::sioS5Line, power_control::sioS5Event))
2204 {
2205 return -1;
2206 }
2207 }
2208 else
2209 {
2210 std::cerr << "sioS5 name should be configured from json config file\n";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002211 return -1;
2212 }
2213
2214 // Request POWER_BUTTON GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302215 if (!power_control::powerButtonName.empty())
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002216 {
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302217 if (!power_control::requestGPIOEvents(power_control::powerButtonName,
2218 power_control::powerButtonHandler,
2219 power_control::powerButtonLine,
2220 power_control::powerButtonEvent))
2221 {
2222 return -1;
2223 }
2224 }
2225 else
2226 {
2227 std::cerr
2228 << "powerButton name should be configured from json config file\n";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002229 return -1;
2230 }
2231
2232 // Request RESET_BUTTON GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302233 if (!power_control::resetButtonName.empty())
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002234 {
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302235 if (!power_control::requestGPIOEvents(power_control::resetButtonName,
2236 power_control::resetButtonHandler,
2237 power_control::resetButtonLine,
2238 power_control::resetButtonEvent))
2239 {
2240 return -1;
2241 }
2242 }
2243 else
2244 {
2245 std::cerr
2246 << "resetButton name should be configured from json config file\n";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002247 return -1;
2248 }
2249
2250 // Request NMI_BUTTON GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302251 if (!power_control::nmiButtonName.empty())
2252 {
2253 power_control::requestGPIOEvents(
2254 power_control::nmiButtonName, power_control::nmiButtonHandler,
2255 power_control::nmiButtonLine, power_control::nmiButtonEvent);
2256 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002257
2258 // Request ID_BUTTON GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302259 if (!power_control::idButtonName.empty())
2260 {
2261 power_control::requestGPIOEvents(
2262 power_control::idButtonName, power_control::idButtonHandler,
2263 power_control::idButtonLine, power_control::idButtonEvent);
2264 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002265
2266 // Request POST_COMPLETE GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302267 if (!power_control::postCompleteName.empty())
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002268 {
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302269 if (!power_control::requestGPIOEvents(
2270 power_control::postCompleteName,
2271 power_control::postCompleteHandler,
2272 power_control::postCompleteLine,
2273 power_control::postCompleteEvent))
2274 {
2275 return -1;
2276 }
2277 }
2278 else
2279 {
2280 std::cerr
2281 << "postComplete name should be configured from json config file\n";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002282 return -1;
2283 }
2284
2285 // initialize NMI_OUT GPIO.
Vijay Khemka33a532d2019-11-14 16:50:35 -08002286 power_control::setGPIOOutput(power_control::nmiOutName, 0,
2287 power_control::nmiOutLine);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002288
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002289 // Initialize POWER_OUT and RESET_OUT GPIO.
2290 gpiod::line line;
2291 if (!power_control::setGPIOOutput(power_control::powerOutName, 1, line))
2292 {
2293 return -1;
2294 }
2295
2296 if (!power_control::setGPIOOutput(power_control::resetOutName, 1, line))
2297 {
2298 return -1;
2299 }
2300
2301 // Release line
2302 line.reset();
2303
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002304 // Initialize the power state
2305 power_control::powerState = power_control::PowerState::off;
2306 // Check power good
2307 if (power_control::psPowerOKLine.get_value() > 0)
2308 {
2309 power_control::powerState = power_control::PowerState::on;
2310 }
2311
2312 // Initialize the power state storage
2313 if (power_control::initializePowerStateStorage() < 0)
2314 {
2315 return -1;
2316 }
2317
2318 // Check if we need to start the Power Restore policy
2319 power_control::powerRestorePolicyCheck();
2320
Vijay Khemka33a532d2019-11-14 16:50:35 -08002321 if (power_control::nmiOutLine)
2322 power_control::nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002323
2324 std::cerr << "Initializing power state. ";
2325 power_control::logStateTransition(power_control::powerState);
2326
2327 // Power Control Service
2328 sdbusplus::asio::object_server hostServer =
2329 sdbusplus::asio::object_server(power_control::conn);
2330
2331 // Power Control Interface
2332 power_control::hostIface = hostServer.add_interface(
2333 "/xyz/openbmc_project/state/host0", "xyz.openbmc_project.State.Host");
2334
2335 power_control::hostIface->register_property(
2336 "RequestedHostTransition",
2337 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2338 [](const std::string& requested, std::string& resp) {
2339 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2340 {
2341 sendPowerControlEvent(
2342 power_control::Event::gracefulPowerOffRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002343 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002344 }
2345 else if (requested ==
2346 "xyz.openbmc_project.State.Host.Transition.On")
2347 {
2348 sendPowerControlEvent(power_control::Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002349 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002350 }
2351 else if (requested ==
2352 "xyz.openbmc_project.State.Host.Transition.Reboot")
2353 {
Jason M. Billse7520ba2020-01-31 11:19:03 -08002354 sendPowerControlEvent(power_control::Event::powerCycleRequest);
2355 addRestartCause(power_control::RestartCause::command);
2356 }
2357 else if (requested == "xyz.openbmc_project.State.Host.Transition."
2358 "GracefulWarmReboot")
2359 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002360 sendPowerControlEvent(
2361 power_control::Event::gracefulPowerCycleRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002362 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002363 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002364 else if (requested == "xyz.openbmc_project.State.Host.Transition."
2365 "ForceWarmReboot")
2366 {
2367 sendPowerControlEvent(power_control::Event::resetRequest);
2368 addRestartCause(power_control::RestartCause::command);
2369 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002370 else
2371 {
2372 std::cerr << "Unrecognized host state transition request.\n";
2373 throw std::invalid_argument("Unrecognized Transition Request");
2374 return 0;
2375 }
2376 resp = requested;
2377 return 1;
2378 });
2379 power_control::hostIface->register_property(
2380 "CurrentHostState",
2381 std::string(power_control::getHostState(power_control::powerState)));
2382
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002383 power_control::hostIface->initialize();
2384
2385 // Chassis Control Service
2386 sdbusplus::asio::object_server chassisServer =
2387 sdbusplus::asio::object_server(power_control::conn);
2388
2389 // Chassis Control Interface
2390 power_control::chassisIface =
2391 chassisServer.add_interface("/xyz/openbmc_project/state/chassis0",
2392 "xyz.openbmc_project.State.Chassis");
2393
2394 power_control::chassisIface->register_property(
2395 "RequestedPowerTransition",
2396 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
2397 [](const std::string& requested, std::string& resp) {
2398 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
2399 {
2400 sendPowerControlEvent(power_control::Event::powerOffRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002401 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002402 }
2403 else if (requested ==
2404 "xyz.openbmc_project.State.Chassis.Transition.On")
2405 {
2406 sendPowerControlEvent(power_control::Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002407 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002408 }
2409 else if (requested ==
2410 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2411 {
2412 sendPowerControlEvent(power_control::Event::powerCycleRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002413 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002414 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002415 else
2416 {
2417 std::cerr << "Unrecognized chassis state transition request.\n";
2418 throw std::invalid_argument("Unrecognized Transition Request");
2419 return 0;
2420 }
2421 resp = requested;
2422 return 1;
2423 });
2424 power_control::chassisIface->register_property(
2425 "CurrentPowerState",
2426 std::string(power_control::getChassisState(power_control::powerState)));
2427 power_control::chassisIface->register_property(
2428 "LastStateChangeTime", power_control::getCurrentTimeMs());
2429
2430 power_control::chassisIface->initialize();
2431
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002432 // Chassis System Service
2433 sdbusplus::asio::object_server chassisSysServer =
2434 sdbusplus::asio::object_server(power_control::conn);
2435
2436 // Chassis System Interface
2437 power_control::chassisSysIface = chassisSysServer.add_interface(
2438 "/xyz/openbmc_project/state/chassis_system0",
2439 "xyz.openbmc_project.State.Chassis");
2440
2441 power_control::chassisSysIface->register_property(
2442 "RequestedPowerTransition",
2443 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
2444 [](const std::string& requested, std::string& resp) {
2445 if (requested ==
2446 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2447 {
2448 power_control::systemReset();
2449 addRestartCause(power_control::RestartCause::command);
2450 }
2451 else
2452 {
2453 std::cerr << "Unrecognized chassis system state transition "
2454 "request.\n";
2455 throw std::invalid_argument("Unrecognized Transition Request");
2456 return 0;
2457 }
2458 resp = requested;
2459 return 1;
2460 });
2461 power_control::chassisSysIface->register_property(
2462 "CurrentPowerState",
2463 std::string(power_control::getChassisState(power_control::powerState)));
2464 power_control::chassisSysIface->register_property(
2465 "LastStateChangeTime", power_control::getCurrentTimeMs());
2466
2467 power_control::chassisSysIface->initialize();
2468
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002469 // Buttons Service
2470 sdbusplus::asio::object_server buttonsServer =
2471 sdbusplus::asio::object_server(power_control::conn);
2472
2473 // Power Button Interface
2474 power_control::powerButtonIface = buttonsServer.add_interface(
2475 "/xyz/openbmc_project/chassis/buttons/power",
2476 "xyz.openbmc_project.Chassis.Buttons");
2477
2478 power_control::powerButtonIface->register_property(
2479 "ButtonMasked", false, [](const bool requested, bool& current) {
2480 if (requested)
2481 {
2482 if (power_control::powerButtonMask)
2483 {
2484 return 1;
2485 }
2486 if (!power_control::setGPIOOutput(
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002487 power_control::powerOutName, 1,
2488 power_control::powerButtonMask))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002489 {
2490 throw std::runtime_error("Failed to request GPIO");
2491 return 0;
2492 }
2493 std::cerr << "Power Button Masked.\n";
2494 }
2495 else
2496 {
2497 if (!power_control::powerButtonMask)
2498 {
2499 return 1;
2500 }
2501 std::cerr << "Power Button Un-masked\n";
2502 power_control::powerButtonMask.reset();
2503 }
2504 // Update the mask setting
2505 current = requested;
2506 return 1;
2507 });
2508
2509 // Check power button state
2510 bool powerButtonPressed = power_control::powerButtonLine.get_value() == 0;
2511 power_control::powerButtonIface->register_property("ButtonPressed",
2512 powerButtonPressed);
2513
2514 power_control::powerButtonIface->initialize();
2515
2516 // Reset Button Interface
2517 power_control::resetButtonIface = buttonsServer.add_interface(
2518 "/xyz/openbmc_project/chassis/buttons/reset",
2519 "xyz.openbmc_project.Chassis.Buttons");
2520
2521 power_control::resetButtonIface->register_property(
2522 "ButtonMasked", false, [](const bool requested, bool& current) {
2523 if (requested)
2524 {
2525 if (power_control::resetButtonMask)
2526 {
2527 return 1;
2528 }
2529 if (!power_control::setGPIOOutput(
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002530 power_control::resetOutName, 1,
2531 power_control::resetButtonMask))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002532 {
2533 throw std::runtime_error("Failed to request GPIO");
2534 return 0;
2535 }
2536 std::cerr << "Reset Button Masked.\n";
2537 }
2538 else
2539 {
2540 if (!power_control::resetButtonMask)
2541 {
2542 return 1;
2543 }
2544 std::cerr << "Reset Button Un-masked\n";
2545 power_control::resetButtonMask.reset();
2546 }
2547 // Update the mask setting
2548 current = requested;
2549 return 1;
2550 });
2551
2552 // Check reset button state
2553 bool resetButtonPressed = power_control::resetButtonLine.get_value() == 0;
2554 power_control::resetButtonIface->register_property("ButtonPressed",
2555 resetButtonPressed);
2556
2557 power_control::resetButtonIface->initialize();
2558
Vijay Khemka33a532d2019-11-14 16:50:35 -08002559 if (power_control::nmiButtonLine)
2560 {
2561 // NMI Button Interface
2562 power_control::nmiButtonIface = buttonsServer.add_interface(
2563 "/xyz/openbmc_project/chassis/buttons/nmi",
2564 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002565
Vijay Khemka33a532d2019-11-14 16:50:35 -08002566 power_control::nmiButtonIface->register_property(
2567 "ButtonMasked", false, [](const bool requested, bool& current) {
2568 if (power_control::nmiButtonMasked == requested)
2569 {
2570 // NMI button mask is already set as requested, so no change
2571 return 1;
2572 }
2573 if (requested)
2574 {
2575 std::cerr << "NMI Button Masked.\n";
2576 power_control::nmiButtonMasked = true;
2577 }
2578 else
2579 {
2580 std::cerr << "NMI Button Un-masked.\n";
2581 power_control::nmiButtonMasked = false;
2582 }
2583 // Update the mask setting
2584 current = power_control::nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002585 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08002586 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002587
Vijay Khemka33a532d2019-11-14 16:50:35 -08002588 // Check NMI button state
2589 bool nmiButtonPressed = power_control::nmiButtonLine.get_value() == 0;
2590 power_control::nmiButtonIface->register_property("ButtonPressed",
2591 nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002592
Vijay Khemka33a532d2019-11-14 16:50:35 -08002593 power_control::nmiButtonIface->initialize();
2594 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002595
Vijay Khemka33a532d2019-11-14 16:50:35 -08002596 if (power_control::nmiOutLine)
2597 {
2598 // NMI out Service
2599 sdbusplus::asio::object_server nmiOutServer =
2600 sdbusplus::asio::object_server(power_control::conn);
Chen Yugang174ec662019-08-19 19:58:49 +08002601
Vijay Khemka33a532d2019-11-14 16:50:35 -08002602 // NMI out Interface
2603 power_control::nmiOutIface =
2604 nmiOutServer.add_interface("/xyz/openbmc_project/control/host0/nmi",
2605 "xyz.openbmc_project.Control.Host.NMI");
2606 power_control::nmiOutIface->register_method("NMI",
2607 power_control::nmiReset);
2608 power_control::nmiOutIface->initialize();
2609 }
Chen Yugang174ec662019-08-19 19:58:49 +08002610
Vijay Khemka33a532d2019-11-14 16:50:35 -08002611 if (power_control::idButtonLine)
2612 {
2613 // ID Button Interface
2614 power_control::idButtonIface = buttonsServer.add_interface(
2615 "/xyz/openbmc_project/chassis/buttons/id",
2616 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002617
Vijay Khemka33a532d2019-11-14 16:50:35 -08002618 // Check ID button state
2619 bool idButtonPressed = power_control::idButtonLine.get_value() == 0;
2620 power_control::idButtonIface->register_property("ButtonPressed",
2621 idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002622
Vijay Khemka33a532d2019-11-14 16:50:35 -08002623 power_control::idButtonIface->initialize();
2624 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002625
2626 // OS State Service
2627 sdbusplus::asio::object_server osServer =
2628 sdbusplus::asio::object_server(power_control::conn);
2629
2630 // OS State Interface
2631 power_control::osIface = osServer.add_interface(
2632 "/xyz/openbmc_project/state/os",
2633 "xyz.openbmc_project.State.OperatingSystem.Status");
2634
2635 // Get the initial OS state based on POST complete
2636 // 0: Asserted, OS state is "Standby" (ready to boot)
2637 // 1: De-Asserted, OS state is "Inactive"
2638 std::string osState = power_control::postCompleteLine.get_value() > 0
2639 ? "Inactive"
2640 : "Standby";
2641
2642 power_control::osIface->register_property("OperatingSystemState",
2643 std::string(osState));
2644
2645 power_control::osIface->initialize();
2646
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002647 // Restart Cause Service
2648 sdbusplus::asio::object_server restartCauseServer =
2649 sdbusplus::asio::object_server(power_control::conn);
2650
2651 // Restart Cause Interface
2652 power_control::restartCauseIface = restartCauseServer.add_interface(
2653 "/xyz/openbmc_project/control/host0/restart_cause",
2654 "xyz.openbmc_project.Control.Host.RestartCause");
2655
2656 power_control::restartCauseIface->register_property(
2657 "RestartCause",
2658 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
2659
2660 power_control::restartCauseIface->register_property(
2661 "RequestedRestartCause",
2662 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
2663 [](const std::string& requested, std::string& resp) {
2664 if (requested ==
2665 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
2666 {
2667 power_control::addRestartCause(
2668 power_control::RestartCause::watchdog);
2669 }
2670 else
2671 {
2672 throw std::invalid_argument(
2673 "Unrecognized RestartCause Request");
2674 return 0;
2675 }
2676
2677 std::cerr << "RestartCause requested: " << requested << "\n";
2678 resp = requested;
2679 return 1;
2680 });
2681
2682 power_control::restartCauseIface->initialize();
2683
Yong Li8d660212019-12-27 10:18:10 +08002684 power_control::currentHostStateMonitor();
2685
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002686 power_control::io.run();
2687
2688 return 0;
2689}