blob: 22227354bd62979fe8a7aa6b34407ceb28f2e8b3 [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>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070033#include <string_view>
34
35namespace power_control
36{
37static boost::asio::io_service io;
38std::shared_ptr<sdbusplus::asio::connection> conn;
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053039
40static std::string node = "0";
41
42static std::string powerOutName;
43static std::string powerOkName;
44static std::string resetOutName;
45static std::string nmiOutName;
46static std::string sioPwrGoodName;
47static std::string sioOnControlName;
48static std::string sioS5Name;
49static std::string postCompleteName;
50static std::string powerButtonName;
51static std::string resetButtonName;
52static std::string idButtonName;
53static std::string nmiButtonName;
54
Ed Tanousf61ca6f2019-08-15 15:09:05 -070055static std::shared_ptr<sdbusplus::asio::dbus_interface> hostIface;
56static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisIface;
Vijay Khemka04175c22020-10-09 14:28:11 -070057#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -070058static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSysIface;
Vijay Khemka04175c22020-10-09 14:28:11 -070059#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -070060static std::shared_ptr<sdbusplus::asio::dbus_interface> powerButtonIface;
61static std::shared_ptr<sdbusplus::asio::dbus_interface> resetButtonIface;
62static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiButtonIface;
63static std::shared_ptr<sdbusplus::asio::dbus_interface> osIface;
64static std::shared_ptr<sdbusplus::asio::dbus_interface> idButtonIface;
Chen Yugang174ec662019-08-19 19:58:49 +080065static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiOutIface;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -070066static std::shared_ptr<sdbusplus::asio::dbus_interface> restartCauseIface;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070067
68static gpiod::line powerButtonMask;
69static gpiod::line resetButtonMask;
70static bool nmiButtonMasked = false;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070071
Charles Hsuafd04f02021-04-22 13:52:41 +080072static int powerPulseTimeMs = 200;
73static int forceOffPulseTimeMs = 15000;
74static int resetPulseTimeMs = 500;
75static int powerCycleTimeMs = 5000;
76static int sioPowerGoodWatchdogTimeMs = 1000;
77static int psPowerOKWatchdogTimeMs = 8000;
78static int gracefulPowerOffTimeS = 5 * 60;
79static int warmResetCheckTimeMs = 500;
80static int powerOffSaveTimeMs = 7000;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070081
82const static std::filesystem::path powerControlDir = "/var/lib/power-control";
83const static constexpr std::string_view powerStateFile = "power-state";
84
85static bool nmiEnabled = true;
Priyatharshan P19c47a32020-08-12 18:16:43 +053086static bool sioEnabled = true;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070087
88// Timers
89// Time holding GPIOs asserted
90static boost::asio::steady_timer gpioAssertTimer(io);
91// Time between off and on during a power cycle
92static boost::asio::steady_timer powerCycleTimer(io);
93// Time OS gracefully powering off
94static boost::asio::steady_timer gracefulPowerOffTimer(io);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -070095// Time the warm reset check
96static boost::asio::steady_timer warmResetCheckTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -070097// Time power supply power OK assertion on power-on
98static boost::asio::steady_timer psPowerOKWatchdogTimer(io);
99// Time SIO power good assertion on power-on
100static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io);
101// Time power-off state save for power loss tracking
102static boost::asio::steady_timer powerStateSaveTimer(io);
103// POH timer
104static boost::asio::steady_timer pohCounterTimer(io);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700105// Time when to allow restart cause updates
106static boost::asio::steady_timer restartCauseTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700107
108// GPIO Lines and Event Descriptors
109static gpiod::line psPowerOKLine;
110static boost::asio::posix::stream_descriptor psPowerOKEvent(io);
111static gpiod::line sioPowerGoodLine;
112static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io);
113static gpiod::line sioOnControlLine;
114static boost::asio::posix::stream_descriptor sioOnControlEvent(io);
115static gpiod::line sioS5Line;
116static boost::asio::posix::stream_descriptor sioS5Event(io);
117static gpiod::line powerButtonLine;
118static boost::asio::posix::stream_descriptor powerButtonEvent(io);
119static gpiod::line resetButtonLine;
120static boost::asio::posix::stream_descriptor resetButtonEvent(io);
121static gpiod::line nmiButtonLine;
122static boost::asio::posix::stream_descriptor nmiButtonEvent(io);
123static gpiod::line idButtonLine;
124static boost::asio::posix::stream_descriptor idButtonEvent(io);
125static gpiod::line postCompleteLine;
126static boost::asio::posix::stream_descriptor postCompleteEvent(io);
127static gpiod::line nmiOutLine;
128
129static constexpr uint8_t beepPowerFail = 8;
130
131static void beep(const uint8_t& beepPriority)
132{
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800133 std::string logMsg = "Beep with priority: " + std::to_string(beepPriority);
134 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700135
136 conn->async_method_call(
137 [](boost::system::error_code ec) {
138 if (ec)
139 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800140 std::string errMsg =
141 "beep returned error with async_method_call (ec = " +
142 ec.message();
143 phosphor::logging::log<phosphor::logging::level::ERR>(
144 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700145 return;
146 }
147 },
148 "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
149 "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
150}
151
152enum class PowerState
153{
154 on,
155 waitForPSPowerOK,
156 waitForSIOPowerGood,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700157 off,
158 transitionToOff,
159 gracefulTransitionToOff,
160 cycleOff,
161 transitionToCycleOff,
162 gracefulTransitionToCycleOff,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700163 checkForWarmReset,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700164};
165static PowerState powerState;
166static std::string getPowerStateName(PowerState state)
167{
168 switch (state)
169 {
170 case PowerState::on:
171 return "On";
172 break;
173 case PowerState::waitForPSPowerOK:
174 return "Wait for Power Supply Power OK";
175 break;
176 case PowerState::waitForSIOPowerGood:
177 return "Wait for SIO Power Good";
178 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700179 case PowerState::off:
180 return "Off";
181 break;
182 case PowerState::transitionToOff:
183 return "Transition to Off";
184 break;
185 case PowerState::gracefulTransitionToOff:
186 return "Graceful Transition to Off";
187 break;
188 case PowerState::cycleOff:
189 return "Power Cycle Off";
190 break;
191 case PowerState::transitionToCycleOff:
192 return "Transition to Power Cycle Off";
193 break;
194 case PowerState::gracefulTransitionToCycleOff:
195 return "Graceful Transition to Power Cycle Off";
196 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700197 case PowerState::checkForWarmReset:
198 return "Check for Warm Reset";
199 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700200 default:
201 return "unknown state: " + std::to_string(static_cast<int>(state));
202 break;
203 }
204}
205static void logStateTransition(const PowerState state)
206{
Vijay Khemkad6c5ad12020-05-27 14:57:52 -0700207 std::string logMsg =
208 "Host0: Moving to \"" + getPowerStateName(state) + "\" state";
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700209 phosphor::logging::log<phosphor::logging::level::INFO>(
210 logMsg.c_str(),
Vijay Khemkad6c5ad12020-05-27 14:57:52 -0700211 phosphor::logging::entry("STATE=%s", getPowerStateName(state).c_str()),
212 phosphor::logging::entry("HOST=0"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700213}
214
215enum class Event
216{
217 psPowerOKAssert,
218 psPowerOKDeAssert,
219 sioPowerGoodAssert,
220 sioPowerGoodDeAssert,
221 sioS5Assert,
222 sioS5DeAssert,
Jason M. Billsfb957332021-01-28 13:18:46 -0800223 pltRstAssert,
224 pltRstDeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700225 postCompleteAssert,
226 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700227 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700228 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700229 powerCycleTimerExpired,
230 psPowerOKWatchdogTimerExpired,
231 sioPowerGoodWatchdogTimerExpired,
232 gracefulPowerOffTimerExpired,
233 powerOnRequest,
234 powerOffRequest,
235 powerCycleRequest,
236 resetRequest,
237 gracefulPowerOffRequest,
238 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700239 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700240};
241static std::string getEventName(Event event)
242{
243 switch (event)
244 {
245 case Event::psPowerOKAssert:
246 return "power supply power OK assert";
247 break;
248 case Event::psPowerOKDeAssert:
249 return "power supply power OK de-assert";
250 break;
251 case Event::sioPowerGoodAssert:
252 return "SIO power good assert";
253 break;
254 case Event::sioPowerGoodDeAssert:
255 return "SIO power good de-assert";
256 break;
257 case Event::sioS5Assert:
258 return "SIO S5 assert";
259 break;
260 case Event::sioS5DeAssert:
261 return "SIO S5 de-assert";
262 break;
Jason M. Billsfb957332021-01-28 13:18:46 -0800263 case Event::pltRstAssert:
264 return "PLT_RST assert";
265 break;
266 case Event::pltRstDeAssert:
267 return "PLT_RST de-assert";
268 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700269 case Event::postCompleteAssert:
270 return "POST Complete assert";
271 break;
272 case Event::postCompleteDeAssert:
273 return "POST Complete de-assert";
274 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700275 case Event::powerButtonPressed:
276 return "power button pressed";
277 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700278 case Event::resetButtonPressed:
279 return "reset button pressed";
280 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700281 case Event::powerCycleTimerExpired:
282 return "power cycle timer expired";
283 break;
284 case Event::psPowerOKWatchdogTimerExpired:
285 return "power supply power OK watchdog timer expired";
286 break;
287 case Event::sioPowerGoodWatchdogTimerExpired:
288 return "SIO power good watchdog timer expired";
289 break;
290 case Event::gracefulPowerOffTimerExpired:
291 return "graceful power-off timer expired";
292 break;
293 case Event::powerOnRequest:
294 return "power-on request";
295 break;
296 case Event::powerOffRequest:
297 return "power-off request";
298 break;
299 case Event::powerCycleRequest:
300 return "power-cycle request";
301 break;
302 case Event::resetRequest:
303 return "reset request";
304 break;
305 case Event::gracefulPowerOffRequest:
306 return "graceful power-off request";
307 break;
308 case Event::gracefulPowerCycleRequest:
309 return "graceful power-cycle request";
310 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700311 case Event::warmResetDetected:
312 return "warm reset detected";
313 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700314 default:
315 return "unknown event: " + std::to_string(static_cast<int>(event));
316 break;
317 }
318}
319static void logEvent(const std::string_view stateHandler, const Event event)
320{
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700321 std::string logMsg{stateHandler};
322 logMsg += ": " + getEventName(event) + " event received";
323 phosphor::logging::log<phosphor::logging::level::INFO>(
324 logMsg.c_str(),
325 phosphor::logging::entry("EVENT=%s", getEventName(event).c_str()));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700326}
327
328// Power state handlers
329static void powerStateOn(const Event event);
330static void powerStateWaitForPSPowerOK(const Event event);
331static void powerStateWaitForSIOPowerGood(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700332static void powerStateOff(const Event event);
333static void powerStateTransitionToOff(const Event event);
334static void powerStateGracefulTransitionToOff(const Event event);
335static void powerStateCycleOff(const Event event);
336static void powerStateTransitionToCycleOff(const Event event);
337static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700338static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700339
340static std::function<void(const Event)> getPowerStateHandler(PowerState state)
341{
342 switch (state)
343 {
344 case PowerState::on:
345 return powerStateOn;
346 break;
347 case PowerState::waitForPSPowerOK:
348 return powerStateWaitForPSPowerOK;
349 break;
350 case PowerState::waitForSIOPowerGood:
351 return powerStateWaitForSIOPowerGood;
352 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700353 case PowerState::off:
354 return powerStateOff;
355 break;
356 case PowerState::transitionToOff:
357 return powerStateTransitionToOff;
358 break;
359 case PowerState::gracefulTransitionToOff:
360 return powerStateGracefulTransitionToOff;
361 break;
362 case PowerState::cycleOff:
363 return powerStateCycleOff;
364 break;
365 case PowerState::transitionToCycleOff:
366 return powerStateTransitionToCycleOff;
367 break;
368 case PowerState::gracefulTransitionToCycleOff:
369 return powerStateGracefulTransitionToCycleOff;
370 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700371 case PowerState::checkForWarmReset:
372 return powerStateCheckForWarmReset;
373 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700374 default:
Zev Weiss047bcb52020-08-20 21:28:11 +0000375 return nullptr;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700376 break;
377 }
378};
379
380static void sendPowerControlEvent(const Event event)
381{
382 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
383 if (handler == nullptr)
384 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800385 std::string errMsg = "Failed to find handler for power state: " +
386 std::to_string(static_cast<int>(powerState));
387 phosphor::logging::log<phosphor::logging::level::INFO>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700388 return;
389 }
390 handler(event);
391}
392
393static uint64_t getCurrentTimeMs()
394{
395 struct timespec time = {};
396
397 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
398 {
399 return 0;
400 }
401 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
402 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
403
404 return currentTimeMs;
405}
406
407static constexpr std::string_view getHostState(const PowerState state)
408{
409 switch (state)
410 {
411 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700412 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700413 case PowerState::gracefulTransitionToCycleOff:
414 return "xyz.openbmc_project.State.Host.HostState.Running";
415 break;
416 case PowerState::waitForPSPowerOK:
417 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700418 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700419 case PowerState::transitionToOff:
420 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700421 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700422 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700423 return "xyz.openbmc_project.State.Host.HostState.Off";
424 break;
425 default:
426 return "";
427 break;
428 }
429};
430static constexpr std::string_view getChassisState(const PowerState state)
431{
432 switch (state)
433 {
434 case PowerState::on:
435 case PowerState::transitionToOff:
436 case PowerState::gracefulTransitionToOff:
437 case PowerState::transitionToCycleOff:
438 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700439 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700440 return "xyz.openbmc_project.State.Chassis.PowerState.On";
441 break;
442 case PowerState::waitForPSPowerOK:
443 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700444 case PowerState::off:
445 case PowerState::cycleOff:
446 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
447 break;
448 default:
449 return "";
450 break;
451 }
452};
453static void savePowerState(const PowerState state)
454{
455 powerStateSaveTimer.expires_after(
456 std::chrono::milliseconds(powerOffSaveTimeMs));
457 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
458 if (ec)
459 {
460 // operation_aborted is expected if timer is canceled before
461 // completion.
462 if (ec != boost::asio::error::operation_aborted)
463 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800464 std::string errMsg =
465 "Power-state save async_wait failed: " + ec.message();
466 phosphor::logging::log<phosphor::logging::level::ERR>(
467 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700468 }
469 return;
470 }
471 std::ofstream powerStateStream(powerControlDir / powerStateFile);
472 powerStateStream << getChassisState(state);
473 });
474}
475static void setPowerState(const PowerState state)
476{
477 powerState = state;
478 logStateTransition(state);
479
480 hostIface->set_property("CurrentHostState",
481 std::string(getHostState(powerState)));
482
483 chassisIface->set_property("CurrentPowerState",
484 std::string(getChassisState(powerState)));
485 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
486
487 // Save the power state for the restore policy
488 savePowerState(state);
489}
490
491enum class RestartCause
492{
493 command,
494 resetButton,
495 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700496 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700497 powerPolicyOn,
498 powerPolicyRestore,
499 softReset,
500};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700501static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700502static std::string getRestartCause(RestartCause cause)
503{
504 switch (cause)
505 {
506 case RestartCause::command:
507 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
508 break;
509 case RestartCause::resetButton:
510 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
511 break;
512 case RestartCause::powerButton:
513 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
514 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700515 case RestartCause::watchdog:
516 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
517 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700518 case RestartCause::powerPolicyOn:
519 return "xyz.openbmc_project.State.Host.RestartCause."
520 "PowerPolicyAlwaysOn";
521 break;
522 case RestartCause::powerPolicyRestore:
523 return "xyz.openbmc_project.State.Host.RestartCause."
524 "PowerPolicyPreviousState";
525 break;
526 case RestartCause::softReset:
527 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
528 break;
529 default:
530 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
531 break;
532 }
533}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700534static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700535{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700536 // Add this to the set of causes for this restart
537 causeSet.insert(cause);
538}
539static void clearRestartCause()
540{
541 // Clear the set for the next restart
542 causeSet.clear();
543}
544static void setRestartCauseProperty(const std::string& cause)
545{
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800546 std::string logMsg = "RestartCause set to " + cause;
547 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700548 restartCauseIface->set_property("RestartCause", cause);
549}
Rashmi RV89f61312020-01-22 15:41:50 +0530550
551static void resetACBootProperty()
552{
553 if ((causeSet.contains(RestartCause::command)) ||
554 (causeSet.contains(RestartCause::softReset)))
555 {
556 conn->async_method_call(
557 [](boost::system::error_code ec) {
558 if (ec)
559 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800560 phosphor::logging::log<phosphor::logging::level::ERR>(
561 "failed to reset ACBoot property");
Rashmi RV89f61312020-01-22 15:41:50 +0530562 }
563 },
564 "xyz.openbmc_project.Settings",
565 "/xyz/openbmc_project/control/host0/ac_boot",
566 "org.freedesktop.DBus.Properties", "Set",
567 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
568 std::variant<std::string>{"False"});
569 }
570}
571
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700572static void setRestartCause()
573{
574 // Determine the actual restart cause based on the set of causes
575 std::string restartCause =
576 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
577 if (causeSet.contains(RestartCause::watchdog))
578 {
579 restartCause = getRestartCause(RestartCause::watchdog);
580 }
581 else if (causeSet.contains(RestartCause::command))
582 {
583 restartCause = getRestartCause(RestartCause::command);
584 }
585 else if (causeSet.contains(RestartCause::resetButton))
586 {
587 restartCause = getRestartCause(RestartCause::resetButton);
588 }
589 else if (causeSet.contains(RestartCause::powerButton))
590 {
591 restartCause = getRestartCause(RestartCause::powerButton);
592 }
593 else if (causeSet.contains(RestartCause::powerPolicyOn))
594 {
595 restartCause = getRestartCause(RestartCause::powerPolicyOn);
596 }
597 else if (causeSet.contains(RestartCause::powerPolicyRestore))
598 {
599 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
600 }
601 else if (causeSet.contains(RestartCause::softReset))
602 {
603 restartCause = getRestartCause(RestartCause::softReset);
604 }
605
606 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700607}
608
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700609static void systemPowerGoodFailedLog()
610{
611 sd_journal_send(
612 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
613 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
614 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
615 sioPowerGoodWatchdogTimeMs, NULL);
616}
617
618static void psPowerOKFailedLog()
619{
620 sd_journal_send(
621 "MESSAGE=PowerControl: power supply power good failed to assert",
622 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
623 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
624 psPowerOKWatchdogTimeMs, NULL);
625}
626
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700627static void powerRestorePolicyLog()
628{
629 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
630 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
631 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
632}
633
634static void powerButtonPressLog()
635{
636 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
637 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
638 "OpenBMC.0.1.PowerButtonPressed", NULL);
639}
640
641static void resetButtonPressLog()
642{
643 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
644 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
645 "OpenBMC.0.1.ResetButtonPressed", NULL);
646}
647
648static void nmiButtonPressLog()
649{
650 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
651 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
652 "OpenBMC.0.1.NMIButtonPressed", NULL);
653}
654
655static void nmiDiagIntLog()
656{
657 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
658 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
659 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
660}
661
662static int initializePowerStateStorage()
663{
664 // create the power control directory if it doesn't exist
665 std::error_code ec;
666 if (!(std::filesystem::create_directories(powerControlDir, ec)))
667 {
668 if (ec.value() != 0)
669 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800670 std::string errMsg =
671 "failed to create " + powerControlDir.string() + ec.message();
672 phosphor::logging::log<phosphor::logging::level::ERR>(
673 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700674 return -1;
675 }
676 }
677 // Create the power state file if it doesn't exist
678 if (!std::filesystem::exists(powerControlDir / powerStateFile))
679 {
680 std::ofstream powerStateStream(powerControlDir / powerStateFile);
681 powerStateStream << getChassisState(powerState);
682 }
683 return 0;
684}
685
686static bool wasPowerDropped()
687{
688 std::ifstream powerStateStream(powerControlDir / powerStateFile);
689 if (!powerStateStream.is_open())
690 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800691 phosphor::logging::log<phosphor::logging::level::ERR>(
692 "Failed to open power state file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700693 return false;
694 }
695
696 std::string state;
697 std::getline(powerStateStream, state);
698 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
699}
700
701static void invokePowerRestorePolicy(const std::string& policy)
702{
703 // Async events may call this twice, but we only want to run once
704 static bool policyInvoked = false;
705 if (policyInvoked)
706 {
707 return;
708 }
709 policyInvoked = true;
710
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800711 std::string logMsg = "Power restore delay expired, invoking " + policy;
712 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700713 if (policy ==
714 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
715 {
716 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700717 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700718 }
719 else if (policy == "xyz.openbmc_project.Control.Power.RestorePolicy."
720 "Policy.Restore")
721 {
722 if (wasPowerDropped())
723 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800724 phosphor::logging::log<phosphor::logging::level::INFO>(
725 "Power was dropped, restoring Host On state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700726 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700727 setRestartCauseProperty(
728 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700729 }
730 else
731 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800732 phosphor::logging::log<phosphor::logging::level::INFO>(
733 "No power drop, restoring Host Off state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700734 }
735 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -0700736 // We're done with the previous power state for the restore policy, so store
737 // the current state
738 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700739}
740
741static void powerRestorePolicyDelay(int delay)
742{
743 // Async events may call this twice, but we only want to run once
744 static bool delayStarted = false;
745 if (delayStarted)
746 {
747 return;
748 }
749 delayStarted = true;
750 // Calculate the delay from now to meet the requested delay
751 // Subtract the approximate uboot time
752 static constexpr const int ubootSeconds = 20;
753 delay -= ubootSeconds;
754 // Subtract the time since boot
755 struct sysinfo info = {};
756 if (sysinfo(&info) == 0)
757 {
758 delay -= info.uptime;
759 }
760 // 0 is the minimum delay
761 delay = std::max(delay, 0);
762
763 static boost::asio::steady_timer powerRestorePolicyTimer(io);
764 powerRestorePolicyTimer.expires_after(std::chrono::seconds(delay));
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800765 std::string logMsg =
766 "Power restore delay of " + std::to_string(delay) + " seconds started";
767 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700768 powerRestorePolicyTimer.async_wait([](const boost::system::error_code ec) {
769 if (ec)
770 {
771 // operation_aborted is expected if timer is canceled before
772 // completion.
773 if (ec != boost::asio::error::operation_aborted)
774 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800775 std::string errMsg =
776 "power restore policy async_wait failed: " + ec.message();
777 phosphor::logging::log<phosphor::logging::level::ERR>(
778 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700779 }
780 return;
781 }
782 // Get Power Restore Policy
783 // In case PowerRestorePolicy is not available, set a match for it
784 static std::unique_ptr<sdbusplus::bus::match::match>
785 powerRestorePolicyMatch = std::make_unique<
786 sdbusplus::bus::match::match>(
787 *conn,
788 "type='signal',interface='org.freedesktop.DBus.Properties',"
789 "member='PropertiesChanged',arg0namespace='xyz.openbmc_"
790 "project.Control.Power.RestorePolicy'",
791 [](sdbusplus::message::message& msg) {
792 std::string interfaceName;
793 boost::container::flat_map<std::string,
794 std::variant<std::string>>
795 propertiesChanged;
796 std::string policy;
797 try
798 {
799 msg.read(interfaceName, propertiesChanged);
800 policy = std::get<std::string>(
801 propertiesChanged.begin()->second);
802 }
803 catch (std::exception& e)
804 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800805 phosphor::logging::log<phosphor::logging::level::ERR>(
806 "Unable to read power restore policy value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700807 powerRestorePolicyMatch.reset();
808 return;
809 }
810 invokePowerRestorePolicy(policy);
811 powerRestorePolicyMatch.reset();
812 });
813
814 // Check if it's already on DBus
815 conn->async_method_call(
816 [](boost::system::error_code ec,
817 const std::variant<std::string>& policyProperty) {
818 if (ec)
819 {
820 return;
821 }
822 powerRestorePolicyMatch.reset();
823 const std::string* policy =
824 std::get_if<std::string>(&policyProperty);
825 if (policy == nullptr)
826 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800827 phosphor::logging::log<phosphor::logging::level::ERR>(
828 "Unable to read power restore policy value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700829 return;
830 }
831 invokePowerRestorePolicy(*policy);
832 },
833 "xyz.openbmc_project.Settings",
834 "/xyz/openbmc_project/control/host0/power_restore_policy",
835 "org.freedesktop.DBus.Properties", "Get",
836 "xyz.openbmc_project.Control.Power.RestorePolicy",
837 "PowerRestorePolicy");
838 });
839}
840
841static void powerRestorePolicyStart()
842{
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800843 phosphor::logging::log<phosphor::logging::level::INFO>(
844 "Power restore policy started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700845 powerRestorePolicyLog();
846
847 // Get the desired delay time
848 // In case PowerRestoreDelay is not available, set a match for it
849 static std::unique_ptr<sdbusplus::bus::match::match>
850 powerRestoreDelayMatch = std::make_unique<sdbusplus::bus::match::match>(
851 *conn,
852 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
853 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Control."
854 "Power.RestoreDelay'",
855 [](sdbusplus::message::message& msg) {
856 std::string interfaceName;
857 boost::container::flat_map<std::string, std::variant<uint16_t>>
858 propertiesChanged;
859 int delay = 0;
860 try
861 {
862 msg.read(interfaceName, propertiesChanged);
863 delay =
864 std::get<uint16_t>(propertiesChanged.begin()->second);
865 }
866 catch (std::exception& e)
867 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800868 phosphor::logging::log<phosphor::logging::level::ERR>(
869 "Unable to read power restore delay value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700870 powerRestoreDelayMatch.reset();
871 return;
872 }
873 powerRestorePolicyDelay(delay);
874 powerRestoreDelayMatch.reset();
875 });
876
877 // Check if it's already on DBus
878 conn->async_method_call(
879 [](boost::system::error_code ec,
880 const std::variant<uint16_t>& delayProperty) {
881 if (ec)
882 {
883 return;
884 }
885 powerRestoreDelayMatch.reset();
886 const uint16_t* delay = std::get_if<uint16_t>(&delayProperty);
887 if (delay == nullptr)
888 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800889 phosphor::logging::log<phosphor::logging::level::ERR>(
890 "Unable to read power restore delay value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700891 return;
892 }
893 powerRestorePolicyDelay(*delay);
894 },
895 "xyz.openbmc_project.Settings",
896 "/xyz/openbmc_project/control/power_restore_delay",
897 "org.freedesktop.DBus.Properties", "Get",
898 "xyz.openbmc_project.Control.Power.RestoreDelay", "PowerRestoreDelay");
899}
900
901static void powerRestorePolicyCheck()
902{
903 // In case ACBoot is not available, set a match for it
904 static std::unique_ptr<sdbusplus::bus::match::match> acBootMatch =
905 std::make_unique<sdbusplus::bus::match::match>(
906 *conn,
907 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
908 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Common."
909 "ACBoot'",
910 [](sdbusplus::message::message& msg) {
911 std::string interfaceName;
912 boost::container::flat_map<std::string,
913 std::variant<std::string>>
914 propertiesChanged;
915 std::string acBoot;
916 try
917 {
918 msg.read(interfaceName, propertiesChanged);
919 acBoot = std::get<std::string>(
920 propertiesChanged.begin()->second);
921 }
922 catch (std::exception& e)
923 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800924 phosphor::logging::log<phosphor::logging::level::ERR>(
925 "Unable to read AC Boot status");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700926 acBootMatch.reset();
927 return;
928 }
929 if (acBoot == "Unknown")
930 {
931 return;
932 }
933 if (acBoot == "True")
934 {
935 // Start the Power Restore policy
936 powerRestorePolicyStart();
937 }
938 acBootMatch.reset();
939 });
940
941 // Check if it's already on DBus
942 conn->async_method_call(
943 [](boost::system::error_code ec,
944 const std::variant<std::string>& acBootProperty) {
945 if (ec)
946 {
947 return;
948 }
949 const std::string* acBoot =
950 std::get_if<std::string>(&acBootProperty);
951 if (acBoot == nullptr)
952 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800953 phosphor::logging::log<phosphor::logging::level::ERR>(
954 "Unable to read AC Boot status");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700955 return;
956 }
957 if (*acBoot == "Unknown")
958 {
959 return;
960 }
961 if (*acBoot == "True")
962 {
963 // Start the Power Restore policy
964 powerRestorePolicyStart();
965 }
966 acBootMatch.reset();
967 },
968 "xyz.openbmc_project.Settings",
969 "/xyz/openbmc_project/control/host0/ac_boot",
970 "org.freedesktop.DBus.Properties", "Get",
971 "xyz.openbmc_project.Common.ACBoot", "ACBoot");
972}
973
974static bool requestGPIOEvents(
975 const std::string& name, const std::function<void()>& handler,
976 gpiod::line& gpioLine,
977 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
978{
979 // Find the GPIO line
980 gpioLine = gpiod::find_line(name);
981 if (!gpioLine)
982 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800983 std::string errMsg = "Failed to find the " + name + " line";
984 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700985 return false;
986 }
987
988 try
989 {
990 gpioLine.request(
991 {"power-control", gpiod::line_request::EVENT_BOTH_EDGES});
992 }
993 catch (std::exception&)
994 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800995 std::string errMsg = "Failed to request events for " + name;
996 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700997 return false;
998 }
999
1000 int gpioLineFd = gpioLine.event_get_fd();
1001 if (gpioLineFd < 0)
1002 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001003 std::string errMsg = "Failed to name " + name + " fd";
1004 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001005 return false;
1006 }
1007
1008 gpioEventDescriptor.assign(gpioLineFd);
1009
1010 gpioEventDescriptor.async_wait(
1011 boost::asio::posix::stream_descriptor::wait_read,
1012 [&name, handler](const boost::system::error_code ec) {
1013 if (ec)
1014 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001015 std::string errMsg =
1016 name + " fd handler error: " + ec.message();
1017 phosphor::logging::log<phosphor::logging::level::ERR>(
1018 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001019 // TODO: throw here to force power-control to restart?
1020 return;
1021 }
1022 handler();
1023 });
1024 return true;
1025}
1026
1027static bool setGPIOOutput(const std::string& name, const int value,
1028 gpiod::line& gpioLine)
1029{
1030 // Find the GPIO line
1031 gpioLine = gpiod::find_line(name);
1032 if (!gpioLine)
1033 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001034 std::string errMsg = "Failed to find the " + name + " line";
1035 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001036 return false;
1037 }
1038
1039 // Request GPIO output to specified value
1040 try
1041 {
1042 gpioLine.request({__FUNCTION__, gpiod::line_request::DIRECTION_OUTPUT},
1043 value);
1044 }
1045 catch (std::exception&)
1046 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001047 std::string errMsg = "Failed to request " + name + " output";
1048 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001049 return false;
1050 }
1051
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001052 std::string logMsg = name + " set to " + std::to_string(value);
1053 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001054 return true;
1055}
1056
1057static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1058 const std::string& name, const int value,
1059 const int durationMs)
1060{
1061 // Set the masked GPIO line to the specified value
1062 maskedGPIOLine.set_value(value);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001063 std::string logMsg = name + " set to " + std::to_string(value);
1064 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001065 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001066 gpioAssertTimer.async_wait([maskedGPIOLine, value,
1067 name](const boost::system::error_code ec) {
1068 // Set the masked GPIO line back to the opposite value
1069 maskedGPIOLine.set_value(!value);
1070 std::string logMsg = name + " released";
1071 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
1072 if (ec)
1073 {
1074 // operation_aborted is expected if timer is canceled before
1075 // completion.
1076 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001077 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001078 std::string errMsg =
1079 name + " async_wait failed: " + ec.message();
1080 phosphor::logging::log<phosphor::logging::level::ERR>(
1081 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001082 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001083 }
1084 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001085 return 0;
1086}
1087
1088static int setGPIOOutputForMs(const std::string& name, const int value,
1089 const int durationMs)
1090{
1091 // If the requested GPIO is masked, use the mask line to set the output
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001092 if (powerButtonMask && name == power_control::powerOutName)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001093 {
1094 return setMaskedGPIOOutputForMs(powerButtonMask, name, value,
1095 durationMs);
1096 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001097 if (resetButtonMask && name == power_control::resetOutName)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001098 {
1099 return setMaskedGPIOOutputForMs(resetButtonMask, name, value,
1100 durationMs);
1101 }
1102
1103 // No mask set, so request and set the GPIO normally
1104 gpiod::line gpioLine;
1105 if (!setGPIOOutput(name, value, gpioLine))
1106 {
1107 return -1;
1108 }
1109 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001110 gpioAssertTimer.async_wait([gpioLine, value,
1111 name](const boost::system::error_code ec) {
1112 // Set the GPIO line back to the opposite value
1113 gpioLine.set_value(!value);
1114 std::string logMsg = name + " released";
1115 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
1116 if (ec)
1117 {
1118 // operation_aborted is expected if timer is canceled before
1119 // completion.
1120 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001121 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001122 std::string errMsg =
1123 name + " async_wait failed: " + ec.message();
1124 phosphor::logging::log<phosphor::logging::level::ERR>(
1125 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001126 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001127 }
1128 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001129 return 0;
1130}
1131
1132static void powerOn()
1133{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001134 setGPIOOutputForMs(power_control::powerOutName, 0, powerPulseTimeMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001135}
1136
1137static void gracefulPowerOff()
1138{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001139 setGPIOOutputForMs(power_control::powerOutName, 0, powerPulseTimeMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001140}
1141
1142static void forcePowerOff()
1143{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001144 if (setGPIOOutputForMs(power_control::powerOutName, 0,
1145 forceOffPulseTimeMs) < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001146 {
1147 return;
1148 }
1149
1150 // If the force off timer expires, then the PCH power-button override
1151 // failed, so attempt the Unconditional Powerdown SMBus command.
1152 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1153 if (ec)
1154 {
1155 // operation_aborted is expected if timer is canceled before
1156 // completion.
1157 if (ec != boost::asio::error::operation_aborted)
1158 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001159 std::string errMsg =
1160 "Force power off async_wait failed: " + ec.message();
1161 phosphor::logging::log<phosphor::logging::level::ERR>(
1162 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001163 }
1164 return;
1165 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001166
1167 phosphor::logging::log<phosphor::logging::level::INFO>(
1168 "PCH Power-button override failed. Issuing Unconditional Powerdown "
1169 "SMBus command.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001170 const static constexpr size_t pchDevBusAddress = 3;
1171 const static constexpr size_t pchDevSlaveAddress = 0x44;
1172 const static constexpr size_t pchCmdReg = 0;
1173 const static constexpr size_t pchPowerDownCmd = 0x02;
1174 if (i2cSet(pchDevBusAddress, pchDevSlaveAddress, pchCmdReg,
1175 pchPowerDownCmd) < 0)
1176 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001177 phosphor::logging::log<phosphor::logging::level::ERR>(
1178 "Unconditional Powerdown command failed! Not sure what to do "
1179 "now.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001180 }
1181 });
1182}
1183
1184static void reset()
1185{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001186 setGPIOOutputForMs(power_control::resetOutName, 0, resetPulseTimeMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001187}
1188
1189static void gracefulPowerOffTimerStart()
1190{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001191 phosphor::logging::log<phosphor::logging::level::INFO>(
1192 "Graceful power-off timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001193 gracefulPowerOffTimer.expires_after(
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001194 std::chrono::seconds(gracefulPowerOffTimeS));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001195 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1196 if (ec)
1197 {
1198 // operation_aborted is expected if timer is canceled before
1199 // completion.
1200 if (ec != boost::asio::error::operation_aborted)
1201 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001202 std::string errMsg =
1203 "Graceful power-off async_wait failed: " + ec.message();
1204 phosphor::logging::log<phosphor::logging::level::ERR>(
1205 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001206 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001207 phosphor::logging::log<phosphor::logging::level::INFO>(
1208 "Graceful power-off timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001209 return;
1210 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001211 phosphor::logging::log<phosphor::logging::level::INFO>(
1212 "Graceful power-off timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001213 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1214 });
1215}
1216
1217static void powerCycleTimerStart()
1218{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001219 phosphor::logging::log<phosphor::logging::level::INFO>(
1220 "Power-cycle timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001221 powerCycleTimer.expires_after(std::chrono::milliseconds(powerCycleTimeMs));
1222 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1223 if (ec)
1224 {
1225 // operation_aborted is expected if timer is canceled before
1226 // completion.
1227 if (ec != boost::asio::error::operation_aborted)
1228 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001229 std::string errMsg =
1230 "Power-cycle async_wait failed: " + ec.message();
1231 phosphor::logging::log<phosphor::logging::level::ERR>(
1232 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001233 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001234 phosphor::logging::log<phosphor::logging::level::INFO>(
1235 "Power-cycle timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001236 return;
1237 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001238 phosphor::logging::log<phosphor::logging::level::INFO>(
1239 "Power-cycle timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001240 sendPowerControlEvent(Event::powerCycleTimerExpired);
1241 });
1242}
1243
1244static void psPowerOKWatchdogTimerStart()
1245{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001246 phosphor::logging::log<phosphor::logging::level::INFO>(
1247 "power supply power OK watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001248 psPowerOKWatchdogTimer.expires_after(
1249 std::chrono::milliseconds(psPowerOKWatchdogTimeMs));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001250 psPowerOKWatchdogTimer.async_wait([](const boost::system::error_code ec) {
1251 if (ec)
1252 {
1253 // operation_aborted is expected if timer is canceled before
1254 // completion.
1255 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001256 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001257 std::string errMsg =
1258 "power supply power OK watchdog async_wait failed: " +
1259 ec.message();
1260 phosphor::logging::log<phosphor::logging::level::ERR>(
1261 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001262 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001263 phosphor::logging::log<phosphor::logging::level::INFO>(
1264 "power supply power OK watchdog timer canceled");
1265 return;
1266 }
1267 phosphor::logging::log<phosphor::logging::level::INFO>(
1268 "power supply power OK watchdog timer expired");
1269 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1270 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001271}
1272
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001273static void warmResetCheckTimerStart()
1274{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001275 phosphor::logging::log<phosphor::logging::level::INFO>(
1276 "Warm reset check timer started");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001277 warmResetCheckTimer.expires_after(
1278 std::chrono::milliseconds(warmResetCheckTimeMs));
1279 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1280 if (ec)
1281 {
1282 // operation_aborted is expected if timer is canceled before
1283 // completion.
1284 if (ec != boost::asio::error::operation_aborted)
1285 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001286 std::string errMsg =
1287 "Warm reset check async_wait failed: " + ec.message();
1288 phosphor::logging::log<phosphor::logging::level::ERR>(
1289 errMsg.c_str());
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001290 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001291 phosphor::logging::log<phosphor::logging::level::INFO>(
1292 "Warm reset check timer canceled");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001293 return;
1294 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001295 phosphor::logging::log<phosphor::logging::level::INFO>(
1296 "Warm reset check timer completed");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001297 sendPowerControlEvent(Event::warmResetDetected);
1298 });
1299}
1300
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001301static void pohCounterTimerStart()
1302{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001303 phosphor::logging::log<phosphor::logging::level::INFO>("POH timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001304 // Set the time-out as 1 hour, to align with POH command in ipmid
1305 pohCounterTimer.expires_after(std::chrono::hours(1));
1306 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1307 if (ec)
1308 {
1309 // operation_aborted is expected if timer is canceled before
1310 // completion.
1311 if (ec != boost::asio::error::operation_aborted)
1312 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001313 std::string errMsg =
1314 "POH timer async_wait failed: " + ec.message();
1315 phosphor::logging::log<phosphor::logging::level::ERR>(
1316 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001317 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001318 phosphor::logging::log<phosphor::logging::level::INFO>(
1319 "POH timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001320 return;
1321 }
1322
1323 if (getHostState(powerState) !=
1324 "xyz.openbmc_project.State.Host.HostState.Running")
1325 {
1326 return;
1327 }
1328
1329 conn->async_method_call(
1330 [](boost::system::error_code ec,
1331 const std::variant<uint32_t>& pohCounterProperty) {
1332 if (ec)
1333 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001334 phosphor::logging::log<phosphor::logging::level::INFO>(
1335 "error to get poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001336 return;
1337 }
1338 const uint32_t* pohCounter =
1339 std::get_if<uint32_t>(&pohCounterProperty);
1340 if (pohCounter == nullptr)
1341 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001342 phosphor::logging::log<phosphor::logging::level::INFO>(
1343 "unable to read poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001344 return;
1345 }
1346
1347 conn->async_method_call(
1348 [](boost::system::error_code ec) {
1349 if (ec)
1350 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001351 phosphor::logging::log<
1352 phosphor::logging::level::INFO>(
1353 "failed to set poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001354 }
1355 },
1356 "xyz.openbmc_project.Settings",
1357 "/xyz/openbmc_project/state/chassis0",
1358 "org.freedesktop.DBus.Properties", "Set",
1359 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1360 std::variant<uint32_t>(*pohCounter + 1));
1361 },
1362 "xyz.openbmc_project.Settings",
1363 "/xyz/openbmc_project/state/chassis0",
1364 "org.freedesktop.DBus.Properties", "Get",
1365 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1366
1367 pohCounterTimerStart();
1368 });
1369}
1370
1371static void currentHostStateMonitor()
1372{
Yong Li8d660212019-12-27 10:18:10 +08001373 if (getHostState(powerState) ==
1374 "xyz.openbmc_project.State.Host.HostState.Running")
1375 {
1376 pohCounterTimerStart();
1377 // Clear the restart cause set for the next restart
1378 clearRestartCause();
1379 }
1380 else
1381 {
1382 pohCounterTimer.cancel();
1383 // Set the restart cause set for this restart
1384 setRestartCause();
1385 }
1386
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001387 static auto match = sdbusplus::bus::match::match(
1388 *conn,
1389 "type='signal',member='PropertiesChanged', "
1390 "interface='org.freedesktop.DBus.Properties', "
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001391 "arg0='xyz.openbmc_project.State.Host'",
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001392 [](sdbusplus::message::message& message) {
1393 std::string intfName;
1394 std::map<std::string, std::variant<std::string>> properties;
1395
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001396 try
1397 {
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001398 message.read(intfName, properties);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001399 }
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001400 catch (std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001401 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001402 phosphor::logging::log<phosphor::logging::level::ERR>(
1403 "Unable to read host state");
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001404 return;
1405 }
1406 if (properties.empty())
1407 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001408 phosphor::logging::log<phosphor::logging::level::ERR>(
1409 "ERROR: Empty PropertiesChanged signal received");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001410 return;
1411 }
1412
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001413 // We only want to check for CurrentHostState
1414 if (properties.begin()->first != "CurrentHostState")
1415 {
1416 return;
1417 }
1418 std::string* currentHostState =
1419 std::get_if<std::string>(&(properties.begin()->second));
1420 if (currentHostState == nullptr)
1421 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001422 std::string errMsg =
1423 properties.begin()->first + " property invalid";
1424 phosphor::logging::log<phosphor::logging::level::ERR>(
1425 errMsg.c_str());
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001426 return;
1427 }
1428
1429 if (*currentHostState ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001430 "xyz.openbmc_project.State.Host.HostState.Running")
1431 {
1432 pohCounterTimerStart();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001433 // Clear the restart cause set for the next restart
1434 clearRestartCause();
Yong Li8d660212019-12-27 10:18:10 +08001435 sd_journal_send("MESSAGE=Host system DC power is on",
1436 "PRIORITY=%i", LOG_INFO,
1437 "REDFISH_MESSAGE_ID=%s",
1438 "OpenBMC.0.1.DCPowerOn", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001439 }
1440 else
1441 {
1442 pohCounterTimer.cancel();
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301443 // POST_COMPLETE GPIO event is not working in some platforms
1444 // when power state is changed to OFF. This resulted in
1445 // 'OperatingSystemState' to stay at 'Standby', even though
1446 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1447 // if HostState is trurned to OFF.
1448 osIface->set_property("OperatingSystemState",
1449 std::string("Inactive"));
1450
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001451 // Set the restart cause set for this restart
1452 setRestartCause();
Rashmi RV89f61312020-01-22 15:41:50 +05301453 resetACBootProperty();
Yong Li8d660212019-12-27 10:18:10 +08001454 sd_journal_send("MESSAGE=Host system DC power is off",
1455 "PRIORITY=%i", LOG_INFO,
1456 "REDFISH_MESSAGE_ID=%s",
1457 "OpenBMC.0.1.DCPowerOff", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001458 }
1459 });
1460}
1461
1462static void sioPowerGoodWatchdogTimerStart()
1463{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001464 phosphor::logging::log<phosphor::logging::level::INFO>(
1465 "SIO power good watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001466 sioPowerGoodWatchdogTimer.expires_after(
1467 std::chrono::milliseconds(sioPowerGoodWatchdogTimeMs));
1468 sioPowerGoodWatchdogTimer.async_wait(
1469 [](const boost::system::error_code ec) {
1470 if (ec)
1471 {
1472 // operation_aborted is expected if timer is canceled before
1473 // completion.
1474 if (ec != boost::asio::error::operation_aborted)
1475 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001476 std::string errMsg =
1477 "SIO power good watchdog async_wait failed: " +
1478 ec.message();
1479 phosphor::logging::log<phosphor::logging::level::ERR>(
1480 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001481 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001482 phosphor::logging::log<phosphor::logging::level::INFO>(
1483 "SIO power good watchdog timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001484 return;
1485 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001486 phosphor::logging::log<phosphor::logging::level::INFO>(
1487 "SIO power good watchdog timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001488 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1489 });
1490}
1491
1492static void powerStateOn(const Event event)
1493{
1494 logEvent(__FUNCTION__, event);
1495 switch (event)
1496 {
1497 case Event::psPowerOKDeAssert:
1498 setPowerState(PowerState::off);
1499 // DC power is unexpectedly lost, beep
1500 beep(beepPowerFail);
1501 break;
1502 case Event::sioS5Assert:
1503 setPowerState(PowerState::transitionToOff);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001504 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001505 break;
Jason M. Billsfb957332021-01-28 13:18:46 -08001506#if USE_PLT_RST
1507 case Event::pltRstAssert:
1508#else
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001509 case Event::postCompleteDeAssert:
Jason M. Billsfb957332021-01-28 13:18:46 -08001510#endif
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001511 setPowerState(PowerState::checkForWarmReset);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001512 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001513 warmResetCheckTimerStart();
1514 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001515 case Event::powerButtonPressed:
1516 setPowerState(PowerState::gracefulTransitionToOff);
1517 gracefulPowerOffTimerStart();
1518 break;
1519 case Event::powerOffRequest:
1520 setPowerState(PowerState::transitionToOff);
1521 forcePowerOff();
1522 break;
1523 case Event::gracefulPowerOffRequest:
1524 setPowerState(PowerState::gracefulTransitionToOff);
1525 gracefulPowerOffTimerStart();
1526 gracefulPowerOff();
1527 break;
1528 case Event::powerCycleRequest:
1529 setPowerState(PowerState::transitionToCycleOff);
1530 forcePowerOff();
1531 break;
1532 case Event::gracefulPowerCycleRequest:
1533 setPowerState(PowerState::gracefulTransitionToCycleOff);
1534 gracefulPowerOffTimerStart();
1535 gracefulPowerOff();
1536 break;
1537 case Event::resetRequest:
1538 reset();
1539 break;
1540 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001541 phosphor::logging::log<phosphor::logging::level::INFO>(
1542 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001543 break;
1544 }
1545}
1546
1547static void powerStateWaitForPSPowerOK(const Event event)
1548{
1549 logEvent(__FUNCTION__, event);
1550 switch (event)
1551 {
1552 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301553 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001554 // Cancel any GPIO assertions held during the transition
1555 gpioAssertTimer.cancel();
1556 psPowerOKWatchdogTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301557 if (sioEnabled == true)
1558 {
1559 sioPowerGoodWatchdogTimerStart();
1560 setPowerState(PowerState::waitForSIOPowerGood);
1561 }
1562 else
1563 {
1564 setPowerState(PowerState::on);
1565 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001566 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301567 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001568 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001569 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001570 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001571 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001572 case Event::sioPowerGoodAssert:
1573 psPowerOKWatchdogTimer.cancel();
1574 setPowerState(PowerState::on);
1575 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001576 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001577 phosphor::logging::log<phosphor::logging::level::INFO>(
1578 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001579 break;
1580 }
1581}
1582
1583static void powerStateWaitForSIOPowerGood(const Event event)
1584{
1585 logEvent(__FUNCTION__, event);
1586 switch (event)
1587 {
1588 case Event::sioPowerGoodAssert:
1589 sioPowerGoodWatchdogTimer.cancel();
1590 setPowerState(PowerState::on);
1591 break;
1592 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001593 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001594 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001595 break;
1596 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001597 phosphor::logging::log<phosphor::logging::level::INFO>(
1598 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001599 break;
1600 }
1601}
1602
1603static void powerStateOff(const Event event)
1604{
1605 logEvent(__FUNCTION__, event);
1606 switch (event)
1607 {
1608 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301609 {
1610 if (sioEnabled == true)
1611 {
1612 setPowerState(PowerState::waitForSIOPowerGood);
1613 }
1614 else
1615 {
1616 setPowerState(PowerState::on);
1617 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001618 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301619 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001620 case Event::sioS5DeAssert:
1621 setPowerState(PowerState::waitForPSPowerOK);
1622 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001623 case Event::sioPowerGoodAssert:
1624 setPowerState(PowerState::on);
1625 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001626 case Event::powerButtonPressed:
1627 psPowerOKWatchdogTimerStart();
1628 setPowerState(PowerState::waitForPSPowerOK);
1629 break;
1630 case Event::powerOnRequest:
1631 psPowerOKWatchdogTimerStart();
1632 setPowerState(PowerState::waitForPSPowerOK);
1633 powerOn();
1634 break;
1635 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001636 phosphor::logging::log<phosphor::logging::level::INFO>(
1637 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001638 break;
1639 }
1640}
1641
1642static void powerStateTransitionToOff(const Event event)
1643{
1644 logEvent(__FUNCTION__, event);
1645 switch (event)
1646 {
1647 case Event::psPowerOKDeAssert:
1648 // Cancel any GPIO assertions held during the transition
1649 gpioAssertTimer.cancel();
1650 setPowerState(PowerState::off);
1651 break;
1652 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001653 phosphor::logging::log<phosphor::logging::level::INFO>(
1654 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001655 break;
1656 }
1657}
1658
1659static void powerStateGracefulTransitionToOff(const Event event)
1660{
1661 logEvent(__FUNCTION__, event);
1662 switch (event)
1663 {
1664 case Event::psPowerOKDeAssert:
1665 gracefulPowerOffTimer.cancel();
1666 setPowerState(PowerState::off);
1667 break;
1668 case Event::gracefulPowerOffTimerExpired:
1669 setPowerState(PowerState::on);
1670 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001671 case Event::powerOffRequest:
1672 gracefulPowerOffTimer.cancel();
1673 setPowerState(PowerState::transitionToOff);
1674 forcePowerOff();
1675 break;
1676 case Event::powerCycleRequest:
1677 gracefulPowerOffTimer.cancel();
1678 setPowerState(PowerState::transitionToCycleOff);
1679 forcePowerOff();
1680 break;
1681 case Event::resetRequest:
1682 gracefulPowerOffTimer.cancel();
1683 setPowerState(PowerState::on);
1684 reset();
1685 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001686 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001687 phosphor::logging::log<phosphor::logging::level::INFO>(
1688 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001689 break;
1690 }
1691}
1692
1693static void powerStateCycleOff(const Event event)
1694{
1695 logEvent(__FUNCTION__, event);
1696 switch (event)
1697 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001698 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301699 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001700 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301701 if (sioEnabled == true)
1702 {
1703 setPowerState(PowerState::waitForSIOPowerGood);
1704 }
1705 else
1706 {
1707 setPowerState(PowerState::on);
1708 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001709 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301710 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001711 case Event::sioS5DeAssert:
1712 powerCycleTimer.cancel();
1713 setPowerState(PowerState::waitForPSPowerOK);
1714 break;
1715 case Event::powerButtonPressed:
1716 powerCycleTimer.cancel();
1717 psPowerOKWatchdogTimerStart();
1718 setPowerState(PowerState::waitForPSPowerOK);
1719 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001720 case Event::powerCycleTimerExpired:
1721 psPowerOKWatchdogTimerStart();
1722 setPowerState(PowerState::waitForPSPowerOK);
1723 powerOn();
1724 break;
1725 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001726 phosphor::logging::log<phosphor::logging::level::INFO>(
1727 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001728 break;
1729 }
1730}
1731
1732static void powerStateTransitionToCycleOff(const Event event)
1733{
1734 logEvent(__FUNCTION__, event);
1735 switch (event)
1736 {
1737 case Event::psPowerOKDeAssert:
1738 // Cancel any GPIO assertions held during the transition
1739 gpioAssertTimer.cancel();
1740 setPowerState(PowerState::cycleOff);
1741 powerCycleTimerStart();
1742 break;
1743 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001744 phosphor::logging::log<phosphor::logging::level::INFO>(
1745 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001746 break;
1747 }
1748}
1749
1750static void powerStateGracefulTransitionToCycleOff(const Event event)
1751{
1752 logEvent(__FUNCTION__, event);
1753 switch (event)
1754 {
1755 case Event::psPowerOKDeAssert:
1756 gracefulPowerOffTimer.cancel();
1757 setPowerState(PowerState::cycleOff);
1758 powerCycleTimerStart();
1759 break;
1760 case Event::gracefulPowerOffTimerExpired:
1761 setPowerState(PowerState::on);
1762 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001763 case Event::powerOffRequest:
1764 gracefulPowerOffTimer.cancel();
1765 setPowerState(PowerState::transitionToOff);
1766 forcePowerOff();
1767 break;
1768 case Event::powerCycleRequest:
1769 gracefulPowerOffTimer.cancel();
1770 setPowerState(PowerState::transitionToCycleOff);
1771 forcePowerOff();
1772 break;
1773 case Event::resetRequest:
1774 gracefulPowerOffTimer.cancel();
1775 setPowerState(PowerState::on);
1776 reset();
1777 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001778 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001779 phosphor::logging::log<phosphor::logging::level::INFO>(
1780 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001781 break;
1782 }
1783}
1784
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001785static void powerStateCheckForWarmReset(const Event event)
1786{
1787 logEvent(__FUNCTION__, event);
1788 switch (event)
1789 {
1790 case Event::sioS5Assert:
1791 warmResetCheckTimer.cancel();
1792 setPowerState(PowerState::transitionToOff);
1793 break;
1794 case Event::warmResetDetected:
1795 setPowerState(PowerState::on);
1796 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001797 case Event::psPowerOKDeAssert:
1798 warmResetCheckTimer.cancel();
1799 setPowerState(PowerState::off);
1800 // DC power is unexpectedly lost, beep
1801 beep(beepPowerFail);
1802 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001803 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001804 phosphor::logging::log<phosphor::logging::level::INFO>(
1805 "No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001806 break;
1807 }
1808}
1809
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001810static void psPowerOKHandler()
1811{
1812 gpiod::line_event gpioLineEvent = psPowerOKLine.event_read();
1813
1814 Event powerControlEvent =
1815 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
1816 ? Event::psPowerOKAssert
1817 : Event::psPowerOKDeAssert;
1818
1819 sendPowerControlEvent(powerControlEvent);
1820 psPowerOKEvent.async_wait(
1821 boost::asio::posix::stream_descriptor::wait_read,
1822 [](const boost::system::error_code ec) {
1823 if (ec)
1824 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001825 std::string errMsg =
1826 "power supply power OK handler error: " + ec.message();
1827 phosphor::logging::log<phosphor::logging::level::ERR>(
1828 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001829 return;
1830 }
1831 psPowerOKHandler();
1832 });
1833}
1834
1835static void sioPowerGoodHandler()
1836{
1837 gpiod::line_event gpioLineEvent = sioPowerGoodLine.event_read();
1838
1839 Event powerControlEvent =
1840 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
1841 ? Event::sioPowerGoodAssert
1842 : Event::sioPowerGoodDeAssert;
1843
1844 sendPowerControlEvent(powerControlEvent);
1845 sioPowerGoodEvent.async_wait(
1846 boost::asio::posix::stream_descriptor::wait_read,
1847 [](const boost::system::error_code ec) {
1848 if (ec)
1849 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001850 std::string errMsg =
1851 "SIO power good handler error: " + ec.message();
1852 phosphor::logging::log<phosphor::logging::level::ERR>(
1853 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001854 return;
1855 }
1856 sioPowerGoodHandler();
1857 });
1858}
1859
1860static void sioOnControlHandler()
1861{
1862 gpiod::line_event gpioLineEvent = sioOnControlLine.event_read();
1863
1864 bool sioOnControl =
1865 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE;
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001866 std::string logMsg =
1867 "SIO_ONCONTROL value changed: " + std::to_string(sioOnControl);
1868 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001869 sioOnControlEvent.async_wait(
1870 boost::asio::posix::stream_descriptor::wait_read,
1871 [](const boost::system::error_code ec) {
1872 if (ec)
1873 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001874 std::string errMsg =
1875 "SIO ONCONTROL handler error: " + ec.message();
1876 phosphor::logging::log<phosphor::logging::level::ERR>(
1877 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001878 return;
1879 }
1880 sioOnControlHandler();
1881 });
1882}
1883
1884static void sioS5Handler()
1885{
1886 gpiod::line_event gpioLineEvent = sioS5Line.event_read();
1887
1888 Event powerControlEvent =
1889 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE
1890 ? Event::sioS5Assert
1891 : Event::sioS5DeAssert;
1892
1893 sendPowerControlEvent(powerControlEvent);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001894 sioS5Event.async_wait(
1895 boost::asio::posix::stream_descriptor::wait_read,
1896 [](const boost::system::error_code ec) {
1897 if (ec)
1898 {
1899 std::string errMsg = "SIO S5 handler error: " + ec.message();
1900 phosphor::logging::log<phosphor::logging::level::ERR>(
1901 errMsg.c_str());
1902 return;
1903 }
1904 sioS5Handler();
1905 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001906}
1907
1908static void powerButtonHandler()
1909{
1910 gpiod::line_event gpioLineEvent = powerButtonLine.event_read();
1911
1912 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1913 {
1914 powerButtonPressLog();
1915 powerButtonIface->set_property("ButtonPressed", true);
1916 if (!powerButtonMask)
1917 {
1918 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001919 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001920 }
1921 else
1922 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001923 phosphor::logging::log<phosphor::logging::level::INFO>(
1924 "power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001925 }
1926 }
1927 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
1928 {
1929 powerButtonIface->set_property("ButtonPressed", false);
1930 }
1931 powerButtonEvent.async_wait(
1932 boost::asio::posix::stream_descriptor::wait_read,
1933 [](const boost::system::error_code ec) {
1934 if (ec)
1935 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001936 std::string errMsg =
1937 "power button handler error: " + ec.message();
1938 phosphor::logging::log<phosphor::logging::level::ERR>(
1939 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001940 return;
1941 }
1942 powerButtonHandler();
1943 });
1944}
1945
1946static void resetButtonHandler()
1947{
1948 gpiod::line_event gpioLineEvent = resetButtonLine.event_read();
1949
1950 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1951 {
1952 resetButtonPressLog();
1953 resetButtonIface->set_property("ButtonPressed", true);
1954 if (!resetButtonMask)
1955 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001956 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001957 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001958 }
1959 else
1960 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001961 phosphor::logging::log<phosphor::logging::level::INFO>(
1962 "reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001963 }
1964 }
1965 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
1966 {
1967 resetButtonIface->set_property("ButtonPressed", false);
1968 }
1969 resetButtonEvent.async_wait(
1970 boost::asio::posix::stream_descriptor::wait_read,
1971 [](const boost::system::error_code ec) {
1972 if (ec)
1973 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001974 std::string errMsg =
1975 "reset button handler error: " + ec.message();
1976 phosphor::logging::log<phosphor::logging::level::ERR>(
1977 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001978 return;
1979 }
1980 resetButtonHandler();
1981 });
1982}
1983
Vijay Khemka04175c22020-10-09 14:28:11 -07001984#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07001985static constexpr auto systemdBusname = "org.freedesktop.systemd1";
1986static constexpr auto systemdPath = "/org/freedesktop/systemd1";
1987static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
1988static constexpr auto systemTargetName = "chassis-system-reset.target";
1989
1990void systemReset()
1991{
1992 conn->async_method_call(
1993 [](boost::system::error_code ec) {
1994 if (ec)
1995 {
1996 phosphor::logging::log<phosphor::logging::level::ERR>(
1997 "Failed to call chassis system reset",
1998 phosphor::logging::entry("ERR=%s", ec.message().c_str()));
1999 }
2000 },
2001 systemdBusname, systemdPath, systemdInterface, "StartUnit",
2002 systemTargetName, "replace");
2003}
Vijay Khemka04175c22020-10-09 14:28:11 -07002004#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002005
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002006static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002007{
2008 conn->async_method_call(
2009 [](boost::system::error_code ec) {
2010 if (ec)
2011 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002012 phosphor::logging::log<phosphor::logging::level::INFO>(
2013 "failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002014 }
2015 },
Chen Yugang303bd582019-11-01 08:45:06 +08002016 "xyz.openbmc_project.Settings",
2017 "/xyz/openbmc_project/Chassis/Control/NMISource",
2018 "org.freedesktop.DBus.Properties", "Set",
2019 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
2020 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002021}
2022
2023static void nmiReset(void)
2024{
2025 static constexpr const uint8_t value = 1;
2026 const static constexpr int nmiOutPulseTimeMs = 200;
2027
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002028 phosphor::logging::log<phosphor::logging::level::INFO>("NMI out action");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002029 nmiOutLine.set_value(value);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002030 std::string logMsg = nmiOutName + " set to " + std::to_string(value);
2031 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002032 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2033 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2034 // restore the NMI_OUT GPIO line back to the opposite value
2035 nmiOutLine.set_value(!value);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002036 std::string logMsg = nmiOutName + " released";
2037 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002038 if (ec)
2039 {
2040 // operation_aborted is expected if timer is canceled before
2041 // completion.
2042 if (ec != boost::asio::error::operation_aborted)
2043 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002044 std::string errMsg =
2045 nmiOutName + " async_wait failed: " + ec.message();
2046 phosphor::logging::log<phosphor::logging::level::ERR>(
2047 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002048 }
2049 }
2050 });
2051 // log to redfish
2052 nmiDiagIntLog();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002053 phosphor::logging::log<phosphor::logging::level::INFO>(
2054 "NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002055 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002056 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002057}
2058
2059static void nmiSourcePropertyMonitor(void)
2060{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002061 phosphor::logging::log<phosphor::logging::level::INFO>(
2062 "NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002063
2064 static std::unique_ptr<sdbusplus::bus::match::match> nmiSourceMatch =
2065 std::make_unique<sdbusplus::bus::match::match>(
2066 *conn,
2067 "type='signal',interface='org.freedesktop.DBus.Properties',"
Chen Yugang303bd582019-11-01 08:45:06 +08002068 "member='PropertiesChanged',arg0namespace='xyz.openbmc_project."
2069 "Chassis.Control."
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002070 "NMISource'",
2071 [](sdbusplus::message::message& msg) {
2072 std::string interfaceName;
2073 boost::container::flat_map<std::string,
2074 std::variant<bool, std::string>>
2075 propertiesChanged;
2076 std::string state;
2077 bool value = true;
2078 try
2079 {
2080 msg.read(interfaceName, propertiesChanged);
2081 if (propertiesChanged.begin()->first == "Enabled")
2082 {
2083 value =
2084 std::get<bool>(propertiesChanged.begin()->second);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002085 std::string logMsg =
2086 " NMI Enabled propertiesChanged value: " +
2087 std::to_string(value);
2088 phosphor::logging::log<phosphor::logging::level::INFO>(
2089 logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002090 nmiEnabled = value;
2091 if (nmiEnabled)
2092 {
2093 nmiReset();
2094 }
2095 }
2096 }
2097 catch (std::exception& e)
2098 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002099 phosphor::logging::log<phosphor::logging::level::ERR>(
2100 "Unable to read NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002101 return;
2102 }
2103 });
2104}
2105
2106static void setNmiSource()
2107{
2108 conn->async_method_call(
2109 [](boost::system::error_code ec) {
2110 if (ec)
2111 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002112 phosphor::logging::log<phosphor::logging::level::ERR>(
2113 "failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002114 }
2115 },
Chen Yugang303bd582019-11-01 08:45:06 +08002116 "xyz.openbmc_project.Settings",
2117 "/xyz/openbmc_project/Chassis/Control/NMISource",
2118 "org.freedesktop.DBus.Properties", "Set",
2119 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
2120 std::variant<std::string>{"xyz.openbmc_project.Chassis.Control."
2121 "NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002122 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002123 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002124}
2125
2126static void nmiButtonHandler()
2127{
2128 gpiod::line_event gpioLineEvent = nmiButtonLine.event_read();
2129
2130 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2131 {
2132 nmiButtonPressLog();
2133 nmiButtonIface->set_property("ButtonPressed", true);
2134 if (nmiButtonMasked)
2135 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002136 phosphor::logging::log<phosphor::logging::level::INFO>(
2137 "NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002138 }
2139 else
2140 {
2141 setNmiSource();
2142 }
2143 }
2144 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2145 {
2146 nmiButtonIface->set_property("ButtonPressed", false);
2147 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002148 nmiButtonEvent.async_wait(
2149 boost::asio::posix::stream_descriptor::wait_read,
2150 [](const boost::system::error_code ec) {
2151 if (ec)
2152 {
2153 std::string errMsg =
2154 "NMI button handler error: " + ec.message();
2155 phosphor::logging::log<phosphor::logging::level::ERR>(
2156 errMsg.c_str());
2157 return;
2158 }
2159 nmiButtonHandler();
2160 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002161}
2162
2163static void idButtonHandler()
2164{
2165 gpiod::line_event gpioLineEvent = idButtonLine.event_read();
2166
2167 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2168 {
2169 idButtonIface->set_property("ButtonPressed", true);
2170 }
2171 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2172 {
2173 idButtonIface->set_property("ButtonPressed", false);
2174 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002175 idButtonEvent.async_wait(
2176 boost::asio::posix::stream_descriptor::wait_read,
2177 [](const boost::system::error_code& ec) {
2178 if (ec)
2179 {
2180 std::string errMsg = "ID button handler error: " + ec.message();
2181 phosphor::logging::log<phosphor::logging::level::ERR>(
2182 errMsg.c_str());
2183 return;
2184 }
2185 idButtonHandler();
2186 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002187}
2188
Jason M. Billsfb957332021-01-28 13:18:46 -08002189static void pltRstHandler(bool pltRst)
2190{
2191 if (pltRst)
2192 {
2193 sendPowerControlEvent(Event::pltRstDeAssert);
2194 }
2195 else
2196 {
2197 sendPowerControlEvent(Event::pltRstAssert);
2198 }
2199}
2200
2201static void hostMiscHandler(sdbusplus::message::message& msg)
2202{
2203 std::string interfaceName;
2204 boost::container::flat_map<std::string, std::variant<bool>>
2205 propertiesChanged;
2206 bool pltRst;
2207 try
2208 {
2209 msg.read(interfaceName, propertiesChanged);
2210 }
2211 catch (std::exception& e)
2212 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002213 phosphor::logging::log<phosphor::logging::level::ERR>(
2214 "Unable to read Host Misc status");
Jason M. Billsfb957332021-01-28 13:18:46 -08002215 return;
2216 }
2217 if (propertiesChanged.empty())
2218 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002219 phosphor::logging::log<phosphor::logging::level::ERR>(
2220 "ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002221 return;
2222 }
2223
2224 for (auto& [property, value] : propertiesChanged)
2225 {
2226 if (property == "ESpiPlatformReset")
2227 {
2228 bool* pltRst = std::get_if<bool>(&value);
2229 if (pltRst == nullptr)
2230 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002231 std::string errMsg = property + " property invalid";
2232 phosphor::logging::log<phosphor::logging::level::ERR>(
2233 errMsg.c_str());
Jason M. Billsfb957332021-01-28 13:18:46 -08002234 return;
2235 }
2236 pltRstHandler(*pltRst);
2237 }
2238 }
2239}
2240
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002241static void postCompleteHandler()
2242{
2243 gpiod::line_event gpioLineEvent = postCompleteLine.event_read();
2244
2245 bool postComplete =
2246 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002247 if (postComplete)
2248 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002249 sendPowerControlEvent(Event::postCompleteAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002250 osIface->set_property("OperatingSystemState", std::string("Standby"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002251 }
2252 else
2253 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002254 sendPowerControlEvent(Event::postCompleteDeAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002255 osIface->set_property("OperatingSystemState", std::string("Inactive"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002256 }
2257 postCompleteEvent.async_wait(
2258 boost::asio::posix::stream_descriptor::wait_read,
2259 [](const boost::system::error_code ec) {
2260 if (ec)
2261 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002262 std::string errMsg =
2263 "POST complete handler error: " + ec.message();
2264 phosphor::logging::log<phosphor::logging::level::ERR>(
2265 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002266 return;
2267 }
2268 postCompleteHandler();
2269 });
2270}
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302271
2272static int loadConfigValues()
2273{
2274 const std::string configFilePath =
2275 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2276 ".json";
2277 std::ifstream configFile(configFilePath.c_str());
2278 if (!configFile.is_open())
2279 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002280 phosphor::logging::log<phosphor::logging::level::ERR>(
2281 "loadConfigValues : Cannot open config path");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302282 return -1;
2283 }
2284 auto data = nlohmann::json::parse(configFile, nullptr);
2285
2286 if (data.is_discarded())
2287 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002288 phosphor::logging::log<phosphor::logging::level::ERR>(
2289 "Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302290 return -1;
2291 }
Charles Hsuafd04f02021-04-22 13:52:41 +08002292 auto gpios = data["gpio_configs"];
2293 auto timers = data["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302294
Charles Hsuafd04f02021-04-22 13:52:41 +08002295 if (gpios.contains("IdButton"))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302296 {
Charles Hsuafd04f02021-04-22 13:52:41 +08002297 idButtonName = gpios["IdButton"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302298 }
2299
Charles Hsuafd04f02021-04-22 13:52:41 +08002300 if (gpios.contains("NMIButton"))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302301 {
Charles Hsuafd04f02021-04-22 13:52:41 +08002302 nmiButtonName = gpios["NMIButton"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302303 }
2304
Charles Hsuafd04f02021-04-22 13:52:41 +08002305 if (gpios.contains("NMIOut"))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302306 {
Charles Hsuafd04f02021-04-22 13:52:41 +08002307 nmiOutName = gpios["NMIOut"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302308 }
2309
Charles Hsuafd04f02021-04-22 13:52:41 +08002310 if (gpios.contains("PostComplete"))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302311 {
Charles Hsuafd04f02021-04-22 13:52:41 +08002312 postCompleteName = gpios["PostComplete"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302313 }
2314
Charles Hsuafd04f02021-04-22 13:52:41 +08002315 if (gpios.contains("PwrButton"))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302316 {
Charles Hsuafd04f02021-04-22 13:52:41 +08002317 powerButtonName = gpios["PwrButton"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302318 }
2319
Charles Hsuafd04f02021-04-22 13:52:41 +08002320 if (gpios.contains("PwrOK"))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302321 {
Charles Hsuafd04f02021-04-22 13:52:41 +08002322 powerOkName = gpios["PwrOK"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302323 }
2324
Charles Hsuafd04f02021-04-22 13:52:41 +08002325 if (gpios.contains("PwrOut"))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302326 {
Charles Hsuafd04f02021-04-22 13:52:41 +08002327 powerOutName = gpios["PwrOut"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302328 }
2329
Charles Hsuafd04f02021-04-22 13:52:41 +08002330 if (gpios.contains("RstButton"))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302331 {
Charles Hsuafd04f02021-04-22 13:52:41 +08002332 resetButtonName = gpios["RstButton"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302333 }
2334
Charles Hsuafd04f02021-04-22 13:52:41 +08002335 if (gpios.contains("RstOut"))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302336 {
Charles Hsuafd04f02021-04-22 13:52:41 +08002337 resetOutName = gpios["RstOut"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302338 }
2339
Charles Hsuafd04f02021-04-22 13:52:41 +08002340 if (gpios.contains("SIOOnCtl"))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302341 {
Charles Hsuafd04f02021-04-22 13:52:41 +08002342 sioOnControlName = gpios["SIOOnCtl"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302343 }
2344
Charles Hsuafd04f02021-04-22 13:52:41 +08002345 if (gpios.contains("SIOPwrGd"))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302346 {
Charles Hsuafd04f02021-04-22 13:52:41 +08002347 sioPwrGoodName = gpios["SIOPwrGd"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302348 }
2349
Charles Hsuafd04f02021-04-22 13:52:41 +08002350 if (gpios.contains("SIOS5"))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302351 {
Charles Hsuafd04f02021-04-22 13:52:41 +08002352 sioS5Name = gpios["SIOS5"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302353 }
2354
Charles Hsuafd04f02021-04-22 13:52:41 +08002355 if (timers.contains("PowerPulseMs"))
2356 {
2357 powerPulseTimeMs = timers["PowerPulseMs"];
2358 }
2359
2360 if (timers.contains("ForceOffPulseMs"))
2361 {
2362 forceOffPulseTimeMs = timers["ForceOffPulseMs"];
2363 }
2364
2365 if (timers.contains("ResetPulseMs"))
2366 {
2367 resetPulseTimeMs = timers["ResetPulseMs"];
2368 }
2369
2370 if (timers.contains("PowerCycleMs"))
2371 {
2372 powerCycleTimeMs = timers["PowerCycleMs"];
2373 }
2374
2375 if (timers.contains("SioPowerGoodWatchdogMs"))
2376 {
2377 sioPowerGoodWatchdogTimeMs = timers["SioPowerGoodWatchdogMs"];
2378 }
2379
2380 if (timers.contains("PsPowerOKWatchdogMs"))
2381 {
2382 psPowerOKWatchdogTimeMs = timers["PsPowerOKWatchdogMs"];
2383 }
2384
2385 if (timers.contains("GracefulPowerOffS"))
2386 {
2387 gracefulPowerOffTimeS = timers["GracefulPowerOffS"];
2388 }
2389
2390 if (timers.contains("WarmResetCheckMs"))
2391 {
2392 warmResetCheckTimeMs = timers["WarmResetCheckMs"];
2393 }
2394
2395 if (timers.contains("PowerOffSaveMs"))
2396 {
2397 powerOffSaveTimeMs = timers["PowerOffSaveMs"];
2398 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302399 return 0;
2400}
2401
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002402} // namespace power_control
2403
2404int main(int argc, char* argv[])
2405{
Lei YU92caa4c2021-02-23 16:59:25 +08002406 using namespace power_control;
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002407 phosphor::logging::log<phosphor::logging::level::INFO>(
2408 "Start Chassis power control service...");
Lei YU92caa4c2021-02-23 16:59:25 +08002409 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002410
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302411 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08002412 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302413 {
Lei YU92caa4c2021-02-23 16:59:25 +08002414 std::string errMsg = "Host" + node + ": " + "Error in Parsing...";
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002415 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302416 }
2417
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002418 // Request all the dbus names
Lei YU92caa4c2021-02-23 16:59:25 +08002419 conn->request_name("xyz.openbmc_project.State.Host");
2420 conn->request_name("xyz.openbmc_project.State.Chassis");
2421 conn->request_name("xyz.openbmc_project.State.OperatingSystem");
2422 conn->request_name("xyz.openbmc_project.Chassis.Buttons");
2423 conn->request_name("xyz.openbmc_project.Control.Host.NMI");
2424 conn->request_name("xyz.openbmc_project.Control.Host.RestartCause");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002425
Lei YU92caa4c2021-02-23 16:59:25 +08002426 if (sioPwrGoodName.empty() || sioOnControlName.empty() || sioS5Name.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05302427 {
Lei YU92caa4c2021-02-23 16:59:25 +08002428 sioEnabled = false;
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002429 phosphor::logging::log<phosphor::logging::level::INFO>(
2430 "SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05302431 }
2432
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002433 // Request PS_PWROK GPIO events
Lei YU92caa4c2021-02-23 16:59:25 +08002434 if (!powerOkName.empty())
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002435 {
Lei YU92caa4c2021-02-23 16:59:25 +08002436 if (!requestGPIOEvents(powerOkName, psPowerOKHandler, psPowerOKLine,
2437 psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302438 {
2439 return -1;
2440 }
2441 }
2442 else
2443 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002444 phosphor::logging::log<phosphor::logging::level::ERR>(
2445 "PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002446 return -1;
2447 }
2448
Lei YU92caa4c2021-02-23 16:59:25 +08002449 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002450 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05302451 // Request SIO_POWER_GOOD GPIO events
Lei YU92caa4c2021-02-23 16:59:25 +08002452 if (!requestGPIOEvents(sioPwrGoodName, sioPowerGoodHandler,
2453 sioPowerGoodLine, sioPowerGoodEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302454 {
2455 return -1;
2456 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002457
Priyatharshan P19c47a32020-08-12 18:16:43 +05302458 // Request SIO_ONCONTROL GPIO events
Lei YU92caa4c2021-02-23 16:59:25 +08002459 if (!requestGPIOEvents(sioOnControlName, sioOnControlHandler,
2460 sioOnControlLine, sioOnControlEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302461 {
2462 return -1;
2463 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002464
Priyatharshan P19c47a32020-08-12 18:16:43 +05302465 // Request SIO_S5 GPIO events
Lei YU92caa4c2021-02-23 16:59:25 +08002466 if (!requestGPIOEvents(sioS5Name, sioS5Handler, sioS5Line, sioS5Event))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302467 {
2468 return -1;
2469 }
2470 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002471
2472 // Request POWER_BUTTON GPIO events
Lei YU92caa4c2021-02-23 16:59:25 +08002473 if (!powerButtonName.empty())
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002474 {
Lei YU92caa4c2021-02-23 16:59:25 +08002475 if (!requestGPIOEvents(powerButtonName, powerButtonHandler,
2476 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302477 {
2478 return -1;
2479 }
2480 }
2481 else
2482 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002483 phosphor::logging::log<phosphor::logging::level::ERR>(
2484 "powerButton name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002485 return -1;
2486 }
2487
2488 // Request RESET_BUTTON GPIO events
Lei YU92caa4c2021-02-23 16:59:25 +08002489 if (!resetButtonName.empty())
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002490 {
Lei YU92caa4c2021-02-23 16:59:25 +08002491 if (!requestGPIOEvents(resetButtonName, resetButtonHandler,
2492 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302493 {
2494 return -1;
2495 }
2496 }
2497 else
2498 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002499 phosphor::logging::log<phosphor::logging::level::INFO>(
2500 "ResetButton not defined...");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002501 }
2502
2503 // Request NMI_BUTTON GPIO events
Lei YU92caa4c2021-02-23 16:59:25 +08002504 if (!nmiButtonName.empty())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302505 {
Lei YU92caa4c2021-02-23 16:59:25 +08002506 requestGPIOEvents(nmiButtonName, nmiButtonHandler, nmiButtonLine,
2507 nmiButtonEvent);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302508 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002509
2510 // Request ID_BUTTON GPIO events
Lei YU92caa4c2021-02-23 16:59:25 +08002511 if (!idButtonName.empty())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302512 {
Lei YU92caa4c2021-02-23 16:59:25 +08002513 requestGPIOEvents(idButtonName, idButtonHandler, idButtonLine,
2514 idButtonEvent);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302515 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002516
Jason M. Billsfb957332021-01-28 13:18:46 -08002517#ifdef USE_PLT_RST
2518 sdbusplus::bus::match::match pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08002519 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08002520 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2521 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08002522 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08002523#endif
2524
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002525 // Request POST_COMPLETE GPIO events
Lei YU92caa4c2021-02-23 16:59:25 +08002526 if (!postCompleteName.empty())
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002527 {
Lei YU92caa4c2021-02-23 16:59:25 +08002528 if (!requestGPIOEvents(postCompleteName, postCompleteHandler,
2529 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302530 {
2531 return -1;
2532 }
2533 }
2534 else
2535 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002536 phosphor::logging::log<phosphor::logging::level::ERR>(
2537 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002538 return -1;
2539 }
2540
2541 // initialize NMI_OUT GPIO.
Lei YU92caa4c2021-02-23 16:59:25 +08002542 setGPIOOutput(nmiOutName, 0, nmiOutLine);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002543
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002544 // Initialize POWER_OUT and RESET_OUT GPIO.
2545 gpiod::line line;
Lei YU92caa4c2021-02-23 16:59:25 +08002546 if (!setGPIOOutput(powerOutName, 1, line))
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002547 {
2548 return -1;
2549 }
2550
Lei YU92caa4c2021-02-23 16:59:25 +08002551 if (!setGPIOOutput(resetOutName, 1, line))
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002552 {
2553 return -1;
2554 }
2555
2556 // Release line
2557 line.reset();
2558
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002559 // Initialize the power state
Lei YU92caa4c2021-02-23 16:59:25 +08002560 powerState = PowerState::off;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002561 // Check power good
Lei YU92caa4c2021-02-23 16:59:25 +08002562 if (psPowerOKLine.get_value() > 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002563 {
Lei YU92caa4c2021-02-23 16:59:25 +08002564 powerState = PowerState::on;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002565 }
2566
2567 // Initialize the power state storage
Lei YU92caa4c2021-02-23 16:59:25 +08002568 if (initializePowerStateStorage() < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002569 {
2570 return -1;
2571 }
2572
2573 // Check if we need to start the Power Restore policy
Lei YU92caa4c2021-02-23 16:59:25 +08002574 powerRestorePolicyCheck();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002575
Lei YU92caa4c2021-02-23 16:59:25 +08002576 if (nmiOutLine)
2577 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002578
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002579 phosphor::logging::log<phosphor::logging::level::INFO>(
2580 "Initializing power state. ");
Lei YU92caa4c2021-02-23 16:59:25 +08002581 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002582
2583 // Power Control Service
2584 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002585 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002586
2587 // Power Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002588 hostIface = hostServer.add_interface("/xyz/openbmc_project/state/host0",
2589 "xyz.openbmc_project.State.Host");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002590
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002591 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08002592 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002593 "RequestedHostTransition",
2594 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2595 [](const std::string& requested, std::string& resp) {
2596 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2597 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002598 // if power button is masked, ignore this
2599 if (!powerButtonMask)
2600 {
2601 sendPowerControlEvent(Event::gracefulPowerOffRequest);
2602 addRestartCause(RestartCause::command);
2603 }
2604 else
2605 {
2606 phosphor::logging::log<phosphor::logging::level::INFO>(
2607 "Power Button Masked.");
2608 throw std::invalid_argument("Transition Request Masked");
2609 return 0;
2610 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002611 }
2612 else if (requested ==
2613 "xyz.openbmc_project.State.Host.Transition.On")
2614 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002615 // if power button is masked, ignore this
2616 if (!powerButtonMask)
2617 {
2618 sendPowerControlEvent(Event::powerOnRequest);
2619 addRestartCause(RestartCause::command);
2620 }
2621 else
2622 {
2623 phosphor::logging::log<phosphor::logging::level::INFO>(
2624 "Power Button Masked.");
2625 throw std::invalid_argument("Transition Request Masked");
2626 return 0;
2627 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002628 }
2629 else if (requested ==
2630 "xyz.openbmc_project.State.Host.Transition.Reboot")
2631 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002632 // if power button is masked, ignore this
2633 if (!powerButtonMask)
2634 {
2635 sendPowerControlEvent(Event::powerCycleRequest);
2636 addRestartCause(RestartCause::command);
2637 }
2638 else
2639 {
2640 phosphor::logging::log<phosphor::logging::level::INFO>(
2641 "Power Button Masked.");
2642 throw std::invalid_argument("Transition Request Masked");
2643 return 0;
2644 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002645 }
2646 else if (requested == "xyz.openbmc_project.State.Host.Transition."
2647 "GracefulWarmReboot")
2648 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002649 // if reset button is masked, ignore this
2650 if (!resetButtonMask)
2651 {
2652 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
2653 addRestartCause(RestartCause::command);
2654 }
2655 else
2656 {
2657 phosphor::logging::log<phosphor::logging::level::INFO>(
2658 "Reset Button Masked.");
2659 throw std::invalid_argument("Transition Request Masked");
2660 return 0;
2661 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002662 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002663 else if (requested == "xyz.openbmc_project.State.Host.Transition."
2664 "ForceWarmReboot")
2665 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002666 // if reset button is masked, ignore this
2667 if (!resetButtonMask)
2668 {
2669 sendPowerControlEvent(Event::resetRequest);
2670 addRestartCause(RestartCause::command);
2671 }
2672 else
2673 {
2674 phosphor::logging::log<phosphor::logging::level::INFO>(
2675 "Reset Button Masked.");
2676 throw std::invalid_argument("Transition Request Masked");
2677 return 0;
2678 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002679 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002680 else
2681 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002682 phosphor::logging::log<phosphor::logging::level::ERR>(
2683 "Unrecognized host state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002684 throw std::invalid_argument("Unrecognized Transition Request");
2685 return 0;
2686 }
2687 resp = requested;
2688 return 1;
2689 });
Lei YU92caa4c2021-02-23 16:59:25 +08002690 hostIface->register_property("CurrentHostState",
2691 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002692
Lei YU92caa4c2021-02-23 16:59:25 +08002693 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002694
2695 // Chassis Control Service
2696 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002697 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002698
2699 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002700 chassisIface =
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002701 chassisServer.add_interface("/xyz/openbmc_project/state/chassis0",
2702 "xyz.openbmc_project.State.Chassis");
2703
Lei YU92caa4c2021-02-23 16:59:25 +08002704 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002705 "RequestedPowerTransition",
2706 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
2707 [](const std::string& requested, std::string& resp) {
2708 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
2709 {
Lei YU92caa4c2021-02-23 16:59:25 +08002710 sendPowerControlEvent(Event::powerOffRequest);
2711 addRestartCause(RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002712 }
2713 else if (requested ==
2714 "xyz.openbmc_project.State.Chassis.Transition.On")
2715 {
Lei YU92caa4c2021-02-23 16:59:25 +08002716 sendPowerControlEvent(Event::powerOnRequest);
2717 addRestartCause(RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002718 }
2719 else if (requested ==
2720 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2721 {
Lei YU92caa4c2021-02-23 16:59:25 +08002722 sendPowerControlEvent(Event::powerCycleRequest);
2723 addRestartCause(RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002724 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002725 else
2726 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002727 phosphor::logging::log<phosphor::logging::level::ERR>(
2728 "Unrecognized chassis state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002729 throw std::invalid_argument("Unrecognized Transition Request");
2730 return 0;
2731 }
2732 resp = requested;
2733 return 1;
2734 });
Lei YU92caa4c2021-02-23 16:59:25 +08002735 chassisIface->register_property("CurrentPowerState",
2736 std::string(getChassisState(powerState)));
2737 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002738
Lei YU92caa4c2021-02-23 16:59:25 +08002739 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002740
Vijay Khemka04175c22020-10-09 14:28:11 -07002741#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002742 // Chassis System Service
2743 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002744 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002745
2746 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002747 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002748 "/xyz/openbmc_project/state/chassis_system0",
2749 "xyz.openbmc_project.State.Chassis");
2750
Lei YU92caa4c2021-02-23 16:59:25 +08002751 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002752 "RequestedPowerTransition",
2753 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
2754 [](const std::string& requested, std::string& resp) {
2755 if (requested ==
2756 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2757 {
Lei YU92caa4c2021-02-23 16:59:25 +08002758 systemReset();
2759 addRestartCause(RestartCause::command);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002760 }
2761 else
2762 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002763 phosphor::logging::log<phosphor::logging::level::ERR>(
2764 "Unrecognized chassis system state transition request.");
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002765 throw std::invalid_argument("Unrecognized Transition Request");
2766 return 0;
2767 }
2768 resp = requested;
2769 return 1;
2770 });
Lei YU92caa4c2021-02-23 16:59:25 +08002771 chassisSysIface->register_property(
2772 "CurrentPowerState", std::string(getChassisState(powerState)));
2773 chassisSysIface->register_property("LastStateChangeTime",
2774 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002775
Lei YU92caa4c2021-02-23 16:59:25 +08002776 chassisSysIface->initialize();
Vijay Khemka04175c22020-10-09 14:28:11 -07002777#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002778
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002779 // Buttons Service
2780 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002781 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002782
2783 // Power Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002784 powerButtonIface = buttonsServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002785 "/xyz/openbmc_project/chassis/buttons/power",
2786 "xyz.openbmc_project.Chassis.Buttons");
2787
Lei YU92caa4c2021-02-23 16:59:25 +08002788 powerButtonIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002789 "ButtonMasked", false, [](const bool requested, bool& current) {
2790 if (requested)
2791 {
Lei YU92caa4c2021-02-23 16:59:25 +08002792 if (powerButtonMask)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002793 {
2794 return 1;
2795 }
Lei YU92caa4c2021-02-23 16:59:25 +08002796 if (!setGPIOOutput(powerOutName, 1, powerButtonMask))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002797 {
2798 throw std::runtime_error("Failed to request GPIO");
2799 return 0;
2800 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002801 phosphor::logging::log<phosphor::logging::level::INFO>(
2802 "Power Button Masked.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002803 }
2804 else
2805 {
Lei YU92caa4c2021-02-23 16:59:25 +08002806 if (!powerButtonMask)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002807 {
2808 return 1;
2809 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002810 phosphor::logging::log<phosphor::logging::level::INFO>(
2811 "Power Button Un-masked");
Lei YU92caa4c2021-02-23 16:59:25 +08002812 powerButtonMask.reset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002813 }
2814 // Update the mask setting
2815 current = requested;
2816 return 1;
2817 });
2818
2819 // Check power button state
Lei YU92caa4c2021-02-23 16:59:25 +08002820 bool powerButtonPressed = powerButtonLine.get_value() == 0;
2821 powerButtonIface->register_property("ButtonPressed", powerButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002822
Lei YU92caa4c2021-02-23 16:59:25 +08002823 powerButtonIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002824
2825 // Reset Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002826 if (!resetButtonName.empty())
John Wang6c090072020-09-30 13:32:16 +08002827 {
Lei YU92caa4c2021-02-23 16:59:25 +08002828 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08002829 "/xyz/openbmc_project/chassis/buttons/reset",
2830 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002831
Lei YU92caa4c2021-02-23 16:59:25 +08002832 resetButtonIface->register_property(
John Wang6c090072020-09-30 13:32:16 +08002833 "ButtonMasked", false, [](const bool requested, bool& current) {
2834 if (requested)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002835 {
Lei YU92caa4c2021-02-23 16:59:25 +08002836 if (resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08002837 {
2838 return 1;
2839 }
Lei YU92caa4c2021-02-23 16:59:25 +08002840 if (!setGPIOOutput(resetOutName, 1, resetButtonMask))
John Wang6c090072020-09-30 13:32:16 +08002841 {
2842 throw std::runtime_error("Failed to request GPIO");
2843 return 0;
2844 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002845 phosphor::logging::log<phosphor::logging::level::INFO>(
2846 "Reset Button Masked.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002847 }
John Wang6c090072020-09-30 13:32:16 +08002848 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002849 {
Lei YU92caa4c2021-02-23 16:59:25 +08002850 if (!resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08002851 {
2852 return 1;
2853 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002854 phosphor::logging::log<phosphor::logging::level::INFO>(
2855 "Reset Button Un-masked");
Lei YU92caa4c2021-02-23 16:59:25 +08002856 resetButtonMask.reset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002857 }
John Wang6c090072020-09-30 13:32:16 +08002858 // Update the mask setting
2859 current = requested;
2860 return 1;
2861 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002862
John Wang6c090072020-09-30 13:32:16 +08002863 // Check reset button state
Lei YU92caa4c2021-02-23 16:59:25 +08002864 bool resetButtonPressed = resetButtonLine.get_value() == 0;
2865 resetButtonIface->register_property("ButtonPressed",
2866 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002867
Lei YU92caa4c2021-02-23 16:59:25 +08002868 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08002869 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002870
Lei YU92caa4c2021-02-23 16:59:25 +08002871 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08002872 {
2873 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002874 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08002875 "/xyz/openbmc_project/chassis/buttons/nmi",
2876 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002877
Lei YU92caa4c2021-02-23 16:59:25 +08002878 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08002879 "ButtonMasked", false, [](const bool requested, bool& current) {
Lei YU92caa4c2021-02-23 16:59:25 +08002880 if (nmiButtonMasked == requested)
Vijay Khemka33a532d2019-11-14 16:50:35 -08002881 {
2882 // NMI button mask is already set as requested, so no change
2883 return 1;
2884 }
2885 if (requested)
2886 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002887 phosphor::logging::log<phosphor::logging::level::INFO>(
2888 "NMI Button Masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08002889 nmiButtonMasked = true;
Vijay Khemka33a532d2019-11-14 16:50:35 -08002890 }
2891 else
2892 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002893 phosphor::logging::log<phosphor::logging::level::INFO>(
2894 "NMI Button Un-masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08002895 nmiButtonMasked = false;
Vijay Khemka33a532d2019-11-14 16:50:35 -08002896 }
2897 // Update the mask setting
Lei YU92caa4c2021-02-23 16:59:25 +08002898 current = nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002899 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08002900 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002901
Vijay Khemka33a532d2019-11-14 16:50:35 -08002902 // Check NMI button state
Lei YU92caa4c2021-02-23 16:59:25 +08002903 bool nmiButtonPressed = nmiButtonLine.get_value() == 0;
2904 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002905
Lei YU92caa4c2021-02-23 16:59:25 +08002906 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08002907 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002908
Lei YU92caa4c2021-02-23 16:59:25 +08002909 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08002910 {
2911 // NMI out Service
2912 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002913 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08002914
Vijay Khemka33a532d2019-11-14 16:50:35 -08002915 // NMI out Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002916 nmiOutIface =
Vijay Khemka33a532d2019-11-14 16:50:35 -08002917 nmiOutServer.add_interface("/xyz/openbmc_project/control/host0/nmi",
2918 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08002919 nmiOutIface->register_method("NMI", nmiReset);
2920 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08002921 }
Chen Yugang174ec662019-08-19 19:58:49 +08002922
Lei YU92caa4c2021-02-23 16:59:25 +08002923 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08002924 {
2925 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002926 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08002927 "/xyz/openbmc_project/chassis/buttons/id",
2928 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002929
Vijay Khemka33a532d2019-11-14 16:50:35 -08002930 // Check ID button state
Lei YU92caa4c2021-02-23 16:59:25 +08002931 bool idButtonPressed = idButtonLine.get_value() == 0;
2932 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002933
Lei YU92caa4c2021-02-23 16:59:25 +08002934 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08002935 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002936
2937 // OS State Service
2938 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002939 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002940
2941 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002942 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002943 "/xyz/openbmc_project/state/os",
2944 "xyz.openbmc_project.State.OperatingSystem.Status");
2945
2946 // Get the initial OS state based on POST complete
2947 // 0: Asserted, OS state is "Standby" (ready to boot)
2948 // 1: De-Asserted, OS state is "Inactive"
Lei YU92caa4c2021-02-23 16:59:25 +08002949 std::string osState =
2950 postCompleteLine.get_value() > 0 ? "Inactive" : "Standby";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002951
Lei YU92caa4c2021-02-23 16:59:25 +08002952 osIface->register_property("OperatingSystemState", std::string(osState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002953
Lei YU92caa4c2021-02-23 16:59:25 +08002954 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002955
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002956 // Restart Cause Service
2957 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002958 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002959
2960 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002961 restartCauseIface = restartCauseServer.add_interface(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002962 "/xyz/openbmc_project/control/host0/restart_cause",
2963 "xyz.openbmc_project.Control.Host.RestartCause");
2964
Lei YU92caa4c2021-02-23 16:59:25 +08002965 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002966 "RestartCause",
2967 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
2968
Lei YU92caa4c2021-02-23 16:59:25 +08002969 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002970 "RequestedRestartCause",
2971 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
2972 [](const std::string& requested, std::string& resp) {
2973 if (requested ==
2974 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
2975 {
Lei YU92caa4c2021-02-23 16:59:25 +08002976 addRestartCause(RestartCause::watchdog);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002977 }
2978 else
2979 {
2980 throw std::invalid_argument(
2981 "Unrecognized RestartCause Request");
2982 return 0;
2983 }
2984
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002985 std::string logMsg = "RestartCause requested: " + requested;
2986 phosphor::logging::log<phosphor::logging::level::INFO>(
2987 logMsg.c_str());
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002988 resp = requested;
2989 return 1;
2990 });
2991
Lei YU92caa4c2021-02-23 16:59:25 +08002992 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002993
Lei YU92caa4c2021-02-23 16:59:25 +08002994 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08002995
Lei YU92caa4c2021-02-23 16:59:25 +08002996 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002997
2998 return 0;
2999}