blob: cc9b57322812f71c9444884da5f1da9182a16a38 [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
72const static constexpr int powerPulseTimeMs = 200;
73const static constexpr int forceOffPulseTimeMs = 15000;
74const static constexpr int resetPulseTimeMs = 500;
Jason M. Billsfc9408a2020-01-31 14:54:17 -080075const static constexpr int powerCycleTimeMs = 5000;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070076const static constexpr int sioPowerGoodWatchdogTimeMs = 1000;
77const static constexpr int psPowerOKWatchdogTimeMs = 8000;
Jason M. Bills22e0bec2021-03-04 12:54:04 -080078const static constexpr int gracefulPowerOffTimeS = 5 * 60;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -070079const static constexpr int warmResetCheckTimeMs = 500;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070080const static constexpr int powerOffSaveTimeMs = 7000;
81
82const static std::filesystem::path powerControlDir = "/var/lib/power-control";
83const static constexpr std::string_view powerStateFile = "power-state";
84
85static bool nmiEnabled = true;
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 }
2292
2293 if (data.contains("IdButton"))
2294 {
2295 idButtonName = data["IdButton"];
2296 }
2297
2298 if (data.contains("NMIButton"))
2299 {
2300 nmiButtonName = data["NMIButton"];
2301 }
2302
2303 if (data.contains("NMIOut"))
2304 {
2305 nmiOutName = data["NMIOut"];
2306 }
2307
2308 if (data.contains("PostComplete"))
2309 {
2310 postCompleteName = data["PostComplete"];
2311 }
2312
2313 if (data.contains("PwrButton"))
2314 {
2315 powerButtonName = data["PwrButton"];
2316 }
2317
2318 if (data.contains("PwrOK"))
2319 {
2320 powerOkName = data["PwrOK"];
2321 }
2322
2323 if (data.contains("PwrOut"))
2324 {
2325 powerOutName = data["PwrOut"];
2326 }
2327
2328 if (data.contains("RstButton"))
2329 {
2330 resetButtonName = data["RstButton"];
2331 }
2332
2333 if (data.contains("RstOut"))
2334 {
2335 resetOutName = data["RstOut"];
2336 }
2337
2338 if (data.contains("SIOOnCtl"))
2339 {
2340 sioOnControlName = data["SIOOnCtl"];
2341 }
2342
2343 if (data.contains("SIOPwrGd"))
2344 {
2345 sioPwrGoodName = data["SIOPwrGd"];
2346 }
2347
2348 if (data.contains("SIOS5"))
2349 {
2350 sioS5Name = data["SIOS5"];
2351 }
2352
2353 return 0;
2354}
2355
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002356} // namespace power_control
2357
2358int main(int argc, char* argv[])
2359{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002360 phosphor::logging::log<phosphor::logging::level::INFO>(
2361 "Start Chassis power control service...");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002362 power_control::conn =
2363 std::make_shared<sdbusplus::asio::connection>(power_control::io);
2364
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302365 // Load GPIO's through json config file
2366 if (power_control::loadConfigValues() == -1)
2367 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002368 std::string errMsg =
2369 "Host" + power_control::node + ": " + "Error in Parsing...";
2370 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302371 }
2372
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002373 // Request all the dbus names
2374 power_control::conn->request_name("xyz.openbmc_project.State.Host");
2375 power_control::conn->request_name("xyz.openbmc_project.State.Chassis");
2376 power_control::conn->request_name(
2377 "xyz.openbmc_project.State.OperatingSystem");
2378 power_control::conn->request_name("xyz.openbmc_project.Chassis.Buttons");
Chen Yugang174ec662019-08-19 19:58:49 +08002379 power_control::conn->request_name("xyz.openbmc_project.Control.Host.NMI");
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002380 power_control::conn->request_name(
2381 "xyz.openbmc_project.Control.Host.RestartCause");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002382
Priyatharshan P19c47a32020-08-12 18:16:43 +05302383 if (power_control::sioPwrGoodName.empty() ||
2384 power_control::sioOnControlName.empty() ||
2385 power_control::sioS5Name.empty())
2386 {
2387 power_control::sioEnabled = false;
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002388 phosphor::logging::log<phosphor::logging::level::INFO>(
2389 "SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05302390 }
2391
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002392 // Request PS_PWROK GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302393 if (!power_control::powerOkName.empty())
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002394 {
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302395 if (!power_control::requestGPIOEvents(
2396 power_control::powerOkName, power_control::psPowerOKHandler,
2397 power_control::psPowerOKLine, power_control::psPowerOKEvent))
2398 {
2399 return -1;
2400 }
2401 }
2402 else
2403 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002404 phosphor::logging::log<phosphor::logging::level::ERR>(
2405 "PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002406 return -1;
2407 }
2408
Priyatharshan P19c47a32020-08-12 18:16:43 +05302409 if (power_control::sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002410 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05302411 // Request SIO_POWER_GOOD GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302412 if (!power_control::requestGPIOEvents(
2413 power_control::sioPwrGoodName,
2414 power_control::sioPowerGoodHandler,
2415 power_control::sioPowerGoodLine,
2416 power_control::sioPowerGoodEvent))
2417 {
2418 return -1;
2419 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002420
Priyatharshan P19c47a32020-08-12 18:16:43 +05302421 // Request SIO_ONCONTROL GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302422 if (!power_control::requestGPIOEvents(
2423 power_control::sioOnControlName,
2424 power_control::sioOnControlHandler,
2425 power_control::sioOnControlLine,
2426 power_control::sioOnControlEvent))
2427 {
2428 return -1;
2429 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002430
Priyatharshan P19c47a32020-08-12 18:16:43 +05302431 // Request SIO_S5 GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302432 if (!power_control::requestGPIOEvents(
2433 power_control::sioS5Name, power_control::sioS5Handler,
2434 power_control::sioS5Line, power_control::sioS5Event))
2435 {
2436 return -1;
2437 }
2438 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002439
2440 // Request POWER_BUTTON GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302441 if (!power_control::powerButtonName.empty())
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002442 {
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302443 if (!power_control::requestGPIOEvents(power_control::powerButtonName,
2444 power_control::powerButtonHandler,
2445 power_control::powerButtonLine,
2446 power_control::powerButtonEvent))
2447 {
2448 return -1;
2449 }
2450 }
2451 else
2452 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002453 phosphor::logging::log<phosphor::logging::level::ERR>(
2454 "powerButton name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002455 return -1;
2456 }
2457
2458 // Request RESET_BUTTON GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302459 if (!power_control::resetButtonName.empty())
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002460 {
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302461 if (!power_control::requestGPIOEvents(power_control::resetButtonName,
2462 power_control::resetButtonHandler,
2463 power_control::resetButtonLine,
2464 power_control::resetButtonEvent))
2465 {
2466 return -1;
2467 }
2468 }
2469 else
2470 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002471 phosphor::logging::log<phosphor::logging::level::INFO>(
2472 "ResetButton not defined...");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002473 }
2474
2475 // Request NMI_BUTTON GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302476 if (!power_control::nmiButtonName.empty())
2477 {
2478 power_control::requestGPIOEvents(
2479 power_control::nmiButtonName, power_control::nmiButtonHandler,
2480 power_control::nmiButtonLine, power_control::nmiButtonEvent);
2481 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002482
2483 // Request ID_BUTTON GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302484 if (!power_control::idButtonName.empty())
2485 {
2486 power_control::requestGPIOEvents(
2487 power_control::idButtonName, power_control::idButtonHandler,
2488 power_control::idButtonLine, power_control::idButtonEvent);
2489 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002490
Jason M. Billsfb957332021-01-28 13:18:46 -08002491#ifdef USE_PLT_RST
2492 sdbusplus::bus::match::match pltRstMatch(
2493 *power_control::conn,
2494 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2495 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
2496 power_control::hostMiscHandler);
2497#endif
2498
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002499 // Request POST_COMPLETE GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302500 if (!power_control::postCompleteName.empty())
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002501 {
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302502 if (!power_control::requestGPIOEvents(
2503 power_control::postCompleteName,
2504 power_control::postCompleteHandler,
2505 power_control::postCompleteLine,
2506 power_control::postCompleteEvent))
2507 {
2508 return -1;
2509 }
2510 }
2511 else
2512 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002513 phosphor::logging::log<phosphor::logging::level::ERR>(
2514 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002515 return -1;
2516 }
2517
2518 // initialize NMI_OUT GPIO.
Vijay Khemka33a532d2019-11-14 16:50:35 -08002519 power_control::setGPIOOutput(power_control::nmiOutName, 0,
2520 power_control::nmiOutLine);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002521
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002522 // Initialize POWER_OUT and RESET_OUT GPIO.
2523 gpiod::line line;
2524 if (!power_control::setGPIOOutput(power_control::powerOutName, 1, line))
2525 {
2526 return -1;
2527 }
2528
2529 if (!power_control::setGPIOOutput(power_control::resetOutName, 1, line))
2530 {
2531 return -1;
2532 }
2533
2534 // Release line
2535 line.reset();
2536
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002537 // Initialize the power state
2538 power_control::powerState = power_control::PowerState::off;
2539 // Check power good
2540 if (power_control::psPowerOKLine.get_value() > 0)
2541 {
2542 power_control::powerState = power_control::PowerState::on;
2543 }
2544
2545 // Initialize the power state storage
2546 if (power_control::initializePowerStateStorage() < 0)
2547 {
2548 return -1;
2549 }
2550
2551 // Check if we need to start the Power Restore policy
2552 power_control::powerRestorePolicyCheck();
2553
Vijay Khemka33a532d2019-11-14 16:50:35 -08002554 if (power_control::nmiOutLine)
2555 power_control::nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002556
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002557 phosphor::logging::log<phosphor::logging::level::INFO>(
2558 "Initializing power state. ");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002559 power_control::logStateTransition(power_control::powerState);
2560
2561 // Power Control Service
2562 sdbusplus::asio::object_server hostServer =
2563 sdbusplus::asio::object_server(power_control::conn);
2564
2565 // Power Control Interface
2566 power_control::hostIface = hostServer.add_interface(
2567 "/xyz/openbmc_project/state/host0", "xyz.openbmc_project.State.Host");
2568
2569 power_control::hostIface->register_property(
2570 "RequestedHostTransition",
2571 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2572 [](const std::string& requested, std::string& resp) {
2573 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2574 {
2575 sendPowerControlEvent(
2576 power_control::Event::gracefulPowerOffRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002577 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002578 }
2579 else if (requested ==
2580 "xyz.openbmc_project.State.Host.Transition.On")
2581 {
2582 sendPowerControlEvent(power_control::Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002583 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002584 }
2585 else if (requested ==
2586 "xyz.openbmc_project.State.Host.Transition.Reboot")
2587 {
Jason M. Billse7520ba2020-01-31 11:19:03 -08002588 sendPowerControlEvent(power_control::Event::powerCycleRequest);
2589 addRestartCause(power_control::RestartCause::command);
2590 }
2591 else if (requested == "xyz.openbmc_project.State.Host.Transition."
2592 "GracefulWarmReboot")
2593 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002594 sendPowerControlEvent(
2595 power_control::Event::gracefulPowerCycleRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002596 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002597 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002598 else if (requested == "xyz.openbmc_project.State.Host.Transition."
2599 "ForceWarmReboot")
2600 {
2601 sendPowerControlEvent(power_control::Event::resetRequest);
2602 addRestartCause(power_control::RestartCause::command);
2603 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002604 else
2605 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002606 phosphor::logging::log<phosphor::logging::level::ERR>(
2607 "Unrecognized host state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002608 throw std::invalid_argument("Unrecognized Transition Request");
2609 return 0;
2610 }
2611 resp = requested;
2612 return 1;
2613 });
2614 power_control::hostIface->register_property(
2615 "CurrentHostState",
2616 std::string(power_control::getHostState(power_control::powerState)));
2617
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002618 power_control::hostIface->initialize();
2619
2620 // Chassis Control Service
2621 sdbusplus::asio::object_server chassisServer =
2622 sdbusplus::asio::object_server(power_control::conn);
2623
2624 // Chassis Control Interface
2625 power_control::chassisIface =
2626 chassisServer.add_interface("/xyz/openbmc_project/state/chassis0",
2627 "xyz.openbmc_project.State.Chassis");
2628
2629 power_control::chassisIface->register_property(
2630 "RequestedPowerTransition",
2631 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
2632 [](const std::string& requested, std::string& resp) {
2633 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
2634 {
2635 sendPowerControlEvent(power_control::Event::powerOffRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002636 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002637 }
2638 else if (requested ==
2639 "xyz.openbmc_project.State.Chassis.Transition.On")
2640 {
2641 sendPowerControlEvent(power_control::Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002642 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002643 }
2644 else if (requested ==
2645 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2646 {
2647 sendPowerControlEvent(power_control::Event::powerCycleRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002648 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002649 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002650 else
2651 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002652 phosphor::logging::log<phosphor::logging::level::ERR>(
2653 "Unrecognized chassis state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002654 throw std::invalid_argument("Unrecognized Transition Request");
2655 return 0;
2656 }
2657 resp = requested;
2658 return 1;
2659 });
2660 power_control::chassisIface->register_property(
2661 "CurrentPowerState",
2662 std::string(power_control::getChassisState(power_control::powerState)));
2663 power_control::chassisIface->register_property(
2664 "LastStateChangeTime", power_control::getCurrentTimeMs());
2665
2666 power_control::chassisIface->initialize();
2667
Vijay Khemka04175c22020-10-09 14:28:11 -07002668#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002669 // Chassis System Service
2670 sdbusplus::asio::object_server chassisSysServer =
2671 sdbusplus::asio::object_server(power_control::conn);
2672
2673 // Chassis System Interface
2674 power_control::chassisSysIface = chassisSysServer.add_interface(
2675 "/xyz/openbmc_project/state/chassis_system0",
2676 "xyz.openbmc_project.State.Chassis");
2677
2678 power_control::chassisSysIface->register_property(
2679 "RequestedPowerTransition",
2680 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
2681 [](const std::string& requested, std::string& resp) {
2682 if (requested ==
2683 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2684 {
2685 power_control::systemReset();
2686 addRestartCause(power_control::RestartCause::command);
2687 }
2688 else
2689 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002690 phosphor::logging::log<phosphor::logging::level::ERR>(
2691 "Unrecognized chassis system state transition request.");
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002692 throw std::invalid_argument("Unrecognized Transition Request");
2693 return 0;
2694 }
2695 resp = requested;
2696 return 1;
2697 });
2698 power_control::chassisSysIface->register_property(
2699 "CurrentPowerState",
2700 std::string(power_control::getChassisState(power_control::powerState)));
2701 power_control::chassisSysIface->register_property(
2702 "LastStateChangeTime", power_control::getCurrentTimeMs());
2703
2704 power_control::chassisSysIface->initialize();
Vijay Khemka04175c22020-10-09 14:28:11 -07002705#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002706
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002707 // Buttons Service
2708 sdbusplus::asio::object_server buttonsServer =
2709 sdbusplus::asio::object_server(power_control::conn);
2710
2711 // Power Button Interface
2712 power_control::powerButtonIface = buttonsServer.add_interface(
2713 "/xyz/openbmc_project/chassis/buttons/power",
2714 "xyz.openbmc_project.Chassis.Buttons");
2715
2716 power_control::powerButtonIface->register_property(
2717 "ButtonMasked", false, [](const bool requested, bool& current) {
2718 if (requested)
2719 {
2720 if (power_control::powerButtonMask)
2721 {
2722 return 1;
2723 }
2724 if (!power_control::setGPIOOutput(
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002725 power_control::powerOutName, 1,
2726 power_control::powerButtonMask))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002727 {
2728 throw std::runtime_error("Failed to request GPIO");
2729 return 0;
2730 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002731 phosphor::logging::log<phosphor::logging::level::INFO>(
2732 "Power Button Masked.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002733 }
2734 else
2735 {
2736 if (!power_control::powerButtonMask)
2737 {
2738 return 1;
2739 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002740 phosphor::logging::log<phosphor::logging::level::INFO>(
2741 "Power Button Un-masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002742 power_control::powerButtonMask.reset();
2743 }
2744 // Update the mask setting
2745 current = requested;
2746 return 1;
2747 });
2748
2749 // Check power button state
2750 bool powerButtonPressed = power_control::powerButtonLine.get_value() == 0;
2751 power_control::powerButtonIface->register_property("ButtonPressed",
2752 powerButtonPressed);
2753
2754 power_control::powerButtonIface->initialize();
2755
2756 // Reset Button Interface
John Wang6c090072020-09-30 13:32:16 +08002757 if (!power_control::resetButtonName.empty())
2758 {
2759 power_control::resetButtonIface = buttonsServer.add_interface(
2760 "/xyz/openbmc_project/chassis/buttons/reset",
2761 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002762
John Wang6c090072020-09-30 13:32:16 +08002763 power_control::resetButtonIface->register_property(
2764 "ButtonMasked", false, [](const bool requested, bool& current) {
2765 if (requested)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002766 {
John Wang6c090072020-09-30 13:32:16 +08002767 if (power_control::resetButtonMask)
2768 {
2769 return 1;
2770 }
2771 if (!power_control::setGPIOOutput(
2772 power_control::resetOutName, 1,
2773 power_control::resetButtonMask))
2774 {
2775 throw std::runtime_error("Failed to request GPIO");
2776 return 0;
2777 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002778 phosphor::logging::log<phosphor::logging::level::INFO>(
2779 "Reset Button Masked.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002780 }
John Wang6c090072020-09-30 13:32:16 +08002781 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002782 {
John Wang6c090072020-09-30 13:32:16 +08002783 if (!power_control::resetButtonMask)
2784 {
2785 return 1;
2786 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002787 phosphor::logging::log<phosphor::logging::level::INFO>(
2788 "Reset Button Un-masked");
John Wang6c090072020-09-30 13:32:16 +08002789 power_control::resetButtonMask.reset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002790 }
John Wang6c090072020-09-30 13:32:16 +08002791 // Update the mask setting
2792 current = requested;
2793 return 1;
2794 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002795
John Wang6c090072020-09-30 13:32:16 +08002796 // Check reset button state
2797 bool resetButtonPressed =
2798 power_control::resetButtonLine.get_value() == 0;
2799 power_control::resetButtonIface->register_property("ButtonPressed",
2800 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002801
John Wang6c090072020-09-30 13:32:16 +08002802 power_control::resetButtonIface->initialize();
2803 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002804
Vijay Khemka33a532d2019-11-14 16:50:35 -08002805 if (power_control::nmiButtonLine)
2806 {
2807 // NMI Button Interface
2808 power_control::nmiButtonIface = buttonsServer.add_interface(
2809 "/xyz/openbmc_project/chassis/buttons/nmi",
2810 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002811
Vijay Khemka33a532d2019-11-14 16:50:35 -08002812 power_control::nmiButtonIface->register_property(
2813 "ButtonMasked", false, [](const bool requested, bool& current) {
2814 if (power_control::nmiButtonMasked == requested)
2815 {
2816 // NMI button mask is already set as requested, so no change
2817 return 1;
2818 }
2819 if (requested)
2820 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002821 phosphor::logging::log<phosphor::logging::level::INFO>(
2822 "NMI Button Masked.");
Vijay Khemka33a532d2019-11-14 16:50:35 -08002823 power_control::nmiButtonMasked = true;
2824 }
2825 else
2826 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002827 phosphor::logging::log<phosphor::logging::level::INFO>(
2828 "NMI Button Un-masked.");
Vijay Khemka33a532d2019-11-14 16:50:35 -08002829 power_control::nmiButtonMasked = false;
2830 }
2831 // Update the mask setting
2832 current = power_control::nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002833 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08002834 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002835
Vijay Khemka33a532d2019-11-14 16:50:35 -08002836 // Check NMI button state
2837 bool nmiButtonPressed = power_control::nmiButtonLine.get_value() == 0;
2838 power_control::nmiButtonIface->register_property("ButtonPressed",
2839 nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002840
Vijay Khemka33a532d2019-11-14 16:50:35 -08002841 power_control::nmiButtonIface->initialize();
2842 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002843
Vijay Khemka33a532d2019-11-14 16:50:35 -08002844 if (power_control::nmiOutLine)
2845 {
2846 // NMI out Service
2847 sdbusplus::asio::object_server nmiOutServer =
2848 sdbusplus::asio::object_server(power_control::conn);
Chen Yugang174ec662019-08-19 19:58:49 +08002849
Vijay Khemka33a532d2019-11-14 16:50:35 -08002850 // NMI out Interface
2851 power_control::nmiOutIface =
2852 nmiOutServer.add_interface("/xyz/openbmc_project/control/host0/nmi",
2853 "xyz.openbmc_project.Control.Host.NMI");
2854 power_control::nmiOutIface->register_method("NMI",
2855 power_control::nmiReset);
2856 power_control::nmiOutIface->initialize();
2857 }
Chen Yugang174ec662019-08-19 19:58:49 +08002858
Vijay Khemka33a532d2019-11-14 16:50:35 -08002859 if (power_control::idButtonLine)
2860 {
2861 // ID Button Interface
2862 power_control::idButtonIface = buttonsServer.add_interface(
2863 "/xyz/openbmc_project/chassis/buttons/id",
2864 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002865
Vijay Khemka33a532d2019-11-14 16:50:35 -08002866 // Check ID button state
2867 bool idButtonPressed = power_control::idButtonLine.get_value() == 0;
2868 power_control::idButtonIface->register_property("ButtonPressed",
2869 idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002870
Vijay Khemka33a532d2019-11-14 16:50:35 -08002871 power_control::idButtonIface->initialize();
2872 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002873
2874 // OS State Service
2875 sdbusplus::asio::object_server osServer =
2876 sdbusplus::asio::object_server(power_control::conn);
2877
2878 // OS State Interface
2879 power_control::osIface = osServer.add_interface(
2880 "/xyz/openbmc_project/state/os",
2881 "xyz.openbmc_project.State.OperatingSystem.Status");
2882
2883 // Get the initial OS state based on POST complete
2884 // 0: Asserted, OS state is "Standby" (ready to boot)
2885 // 1: De-Asserted, OS state is "Inactive"
2886 std::string osState = power_control::postCompleteLine.get_value() > 0
2887 ? "Inactive"
2888 : "Standby";
2889
2890 power_control::osIface->register_property("OperatingSystemState",
2891 std::string(osState));
2892
2893 power_control::osIface->initialize();
2894
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002895 // Restart Cause Service
2896 sdbusplus::asio::object_server restartCauseServer =
2897 sdbusplus::asio::object_server(power_control::conn);
2898
2899 // Restart Cause Interface
2900 power_control::restartCauseIface = restartCauseServer.add_interface(
2901 "/xyz/openbmc_project/control/host0/restart_cause",
2902 "xyz.openbmc_project.Control.Host.RestartCause");
2903
2904 power_control::restartCauseIface->register_property(
2905 "RestartCause",
2906 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
2907
2908 power_control::restartCauseIface->register_property(
2909 "RequestedRestartCause",
2910 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
2911 [](const std::string& requested, std::string& resp) {
2912 if (requested ==
2913 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
2914 {
2915 power_control::addRestartCause(
2916 power_control::RestartCause::watchdog);
2917 }
2918 else
2919 {
2920 throw std::invalid_argument(
2921 "Unrecognized RestartCause Request");
2922 return 0;
2923 }
2924
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002925 std::string logMsg = "RestartCause requested: " + requested;
2926 phosphor::logging::log<phosphor::logging::level::INFO>(
2927 logMsg.c_str());
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002928 resp = requested;
2929 return 1;
2930 });
2931
2932 power_control::restartCauseIface->initialize();
2933
Yong Li8d660212019-12-27 10:18:10 +08002934 power_control::currentHostStateMonitor();
2935
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002936 power_control::io.run();
2937
2938 return 0;
2939}