blob: ab704d8052004dc3efe21b4090752ea03226cc0b [file] [log] [blame]
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001/*
2// Copyright (c) 2018-2019 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#include "i2c.hpp"
17
18#include <sys/sysinfo.h>
19#include <systemd/sd-journal.h>
20
Jason M. Billse63dea02020-08-27 12:07:35 -070021#include <boost/asio/io_service.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070022#include <boost/asio/posix/stream_descriptor.hpp>
Jason M. Billse63dea02020-08-27 12:07:35 -070023#include <boost/asio/steady_timer.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070024#include <boost/container/flat_map.hpp>
Jason M. Bills7d4aaac2019-09-19 14:03:44 -070025#include <boost/container/flat_set.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070026#include <gpiod.hpp>
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053027#include <nlohmann/json.hpp>
Vijay Khemkafc1ecc52020-04-01 10:49:28 -070028#include <phosphor-logging/log.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070029#include <sdbusplus/asio/object_server.hpp>
Vijay Khemka2b6f4422020-05-29 11:13:23 -070030
31#include <filesystem>
32#include <fstream>
33#include <iostream>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070034#include <string_view>
35
36namespace power_control
37{
38static boost::asio::io_service io;
39std::shared_ptr<sdbusplus::asio::connection> conn;
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053040
41static std::string node = "0";
42
43static std::string powerOutName;
44static std::string powerOkName;
45static std::string resetOutName;
46static std::string nmiOutName;
47static std::string sioPwrGoodName;
48static std::string sioOnControlName;
49static std::string sioS5Name;
50static std::string postCompleteName;
51static std::string powerButtonName;
52static std::string resetButtonName;
53static std::string idButtonName;
54static std::string nmiButtonName;
55
Ed Tanousf61ca6f2019-08-15 15:09:05 -070056static std::shared_ptr<sdbusplus::asio::dbus_interface> hostIface;
57static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisIface;
Vijay Khemka04175c22020-10-09 14:28:11 -070058#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -070059static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSysIface;
Vijay Khemka04175c22020-10-09 14:28:11 -070060#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -070061static std::shared_ptr<sdbusplus::asio::dbus_interface> powerButtonIface;
62static std::shared_ptr<sdbusplus::asio::dbus_interface> resetButtonIface;
63static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiButtonIface;
64static std::shared_ptr<sdbusplus::asio::dbus_interface> osIface;
65static std::shared_ptr<sdbusplus::asio::dbus_interface> idButtonIface;
Chen Yugang174ec662019-08-19 19:58:49 +080066static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiOutIface;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -070067static std::shared_ptr<sdbusplus::asio::dbus_interface> restartCauseIface;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070068
69static gpiod::line powerButtonMask;
70static gpiod::line resetButtonMask;
71static bool nmiButtonMasked = false;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070072
73const static constexpr int powerPulseTimeMs = 200;
74const static constexpr int forceOffPulseTimeMs = 15000;
75const static constexpr int resetPulseTimeMs = 500;
Jason M. Billsfc9408a2020-01-31 14:54:17 -080076const static constexpr int powerCycleTimeMs = 5000;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070077const static constexpr int sioPowerGoodWatchdogTimeMs = 1000;
78const static constexpr int psPowerOKWatchdogTimeMs = 8000;
79const static constexpr int gracefulPowerOffTimeMs = 60000;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -070080const static constexpr int warmResetCheckTimeMs = 500;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070081const static constexpr int buttonMaskTimeMs = 60000;
82const static constexpr int powerOffSaveTimeMs = 7000;
83
84const static std::filesystem::path powerControlDir = "/var/lib/power-control";
85const static constexpr std::string_view powerStateFile = "power-state";
86
87static bool nmiEnabled = true;
Priyatharshan P19c47a32020-08-12 18:16:43 +053088static bool sioEnabled = true;
Ed Tanousf61ca6f2019-08-15 15:09:05 -070089
90// Timers
91// Time holding GPIOs asserted
92static boost::asio::steady_timer gpioAssertTimer(io);
93// Time between off and on during a power cycle
94static boost::asio::steady_timer powerCycleTimer(io);
95// Time OS gracefully powering off
96static boost::asio::steady_timer gracefulPowerOffTimer(io);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -070097// Time the warm reset check
98static boost::asio::steady_timer warmResetCheckTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -070099// Time power supply power OK assertion on power-on
100static boost::asio::steady_timer psPowerOKWatchdogTimer(io);
101// Time SIO power good assertion on power-on
102static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io);
103// Time power-off state save for power loss tracking
104static boost::asio::steady_timer powerStateSaveTimer(io);
105// POH timer
106static boost::asio::steady_timer pohCounterTimer(io);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700107// Time when to allow restart cause updates
108static boost::asio::steady_timer restartCauseTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700109
110// GPIO Lines and Event Descriptors
111static gpiod::line psPowerOKLine;
112static boost::asio::posix::stream_descriptor psPowerOKEvent(io);
113static gpiod::line sioPowerGoodLine;
114static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io);
115static gpiod::line sioOnControlLine;
116static boost::asio::posix::stream_descriptor sioOnControlEvent(io);
117static gpiod::line sioS5Line;
118static boost::asio::posix::stream_descriptor sioS5Event(io);
119static gpiod::line powerButtonLine;
120static boost::asio::posix::stream_descriptor powerButtonEvent(io);
121static gpiod::line resetButtonLine;
122static boost::asio::posix::stream_descriptor resetButtonEvent(io);
123static gpiod::line nmiButtonLine;
124static boost::asio::posix::stream_descriptor nmiButtonEvent(io);
125static gpiod::line idButtonLine;
126static boost::asio::posix::stream_descriptor idButtonEvent(io);
127static gpiod::line postCompleteLine;
128static boost::asio::posix::stream_descriptor postCompleteEvent(io);
129static gpiod::line nmiOutLine;
130
131static constexpr uint8_t beepPowerFail = 8;
132
133static void beep(const uint8_t& beepPriority)
134{
135 std::cerr << "Beep with priority: " << (unsigned)beepPriority << "\n";
136
137 conn->async_method_call(
138 [](boost::system::error_code ec) {
139 if (ec)
140 {
141 std::cerr << "beep returned error with "
142 "async_method_call (ec = "
143 << ec << ")\n";
144 return;
145 }
146 },
147 "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
148 "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
149}
150
151enum class PowerState
152{
153 on,
154 waitForPSPowerOK,
155 waitForSIOPowerGood,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700156 off,
157 transitionToOff,
158 gracefulTransitionToOff,
159 cycleOff,
160 transitionToCycleOff,
161 gracefulTransitionToCycleOff,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700162 checkForWarmReset,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700163};
164static PowerState powerState;
165static std::string getPowerStateName(PowerState state)
166{
167 switch (state)
168 {
169 case PowerState::on:
170 return "On";
171 break;
172 case PowerState::waitForPSPowerOK:
173 return "Wait for Power Supply Power OK";
174 break;
175 case PowerState::waitForSIOPowerGood:
176 return "Wait for SIO Power Good";
177 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700178 case PowerState::off:
179 return "Off";
180 break;
181 case PowerState::transitionToOff:
182 return "Transition to Off";
183 break;
184 case PowerState::gracefulTransitionToOff:
185 return "Graceful Transition to Off";
186 break;
187 case PowerState::cycleOff:
188 return "Power Cycle Off";
189 break;
190 case PowerState::transitionToCycleOff:
191 return "Transition to Power Cycle Off";
192 break;
193 case PowerState::gracefulTransitionToCycleOff:
194 return "Graceful Transition to Power Cycle Off";
195 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700196 case PowerState::checkForWarmReset:
197 return "Check for Warm Reset";
198 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700199 default:
200 return "unknown state: " + std::to_string(static_cast<int>(state));
201 break;
202 }
203}
204static void logStateTransition(const PowerState state)
205{
Vijay Khemkad6c5ad12020-05-27 14:57:52 -0700206 std::string logMsg =
207 "Host0: Moving to \"" + getPowerStateName(state) + "\" state";
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700208 phosphor::logging::log<phosphor::logging::level::INFO>(
209 logMsg.c_str(),
Vijay Khemkad6c5ad12020-05-27 14:57:52 -0700210 phosphor::logging::entry("STATE=%s", getPowerStateName(state).c_str()),
211 phosphor::logging::entry("HOST=0"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700212}
213
214enum class Event
215{
216 psPowerOKAssert,
217 psPowerOKDeAssert,
218 sioPowerGoodAssert,
219 sioPowerGoodDeAssert,
220 sioS5Assert,
221 sioS5DeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700222 postCompleteAssert,
223 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700224 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700225 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700226 powerCycleTimerExpired,
227 psPowerOKWatchdogTimerExpired,
228 sioPowerGoodWatchdogTimerExpired,
229 gracefulPowerOffTimerExpired,
230 powerOnRequest,
231 powerOffRequest,
232 powerCycleRequest,
233 resetRequest,
234 gracefulPowerOffRequest,
235 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700236 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700237};
238static std::string getEventName(Event event)
239{
240 switch (event)
241 {
242 case Event::psPowerOKAssert:
243 return "power supply power OK assert";
244 break;
245 case Event::psPowerOKDeAssert:
246 return "power supply power OK de-assert";
247 break;
248 case Event::sioPowerGoodAssert:
249 return "SIO power good assert";
250 break;
251 case Event::sioPowerGoodDeAssert:
252 return "SIO power good de-assert";
253 break;
254 case Event::sioS5Assert:
255 return "SIO S5 assert";
256 break;
257 case Event::sioS5DeAssert:
258 return "SIO S5 de-assert";
259 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700260 case Event::postCompleteAssert:
261 return "POST Complete assert";
262 break;
263 case Event::postCompleteDeAssert:
264 return "POST Complete de-assert";
265 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700266 case Event::powerButtonPressed:
267 return "power button pressed";
268 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700269 case Event::resetButtonPressed:
270 return "reset button pressed";
271 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700272 case Event::powerCycleTimerExpired:
273 return "power cycle timer expired";
274 break;
275 case Event::psPowerOKWatchdogTimerExpired:
276 return "power supply power OK watchdog timer expired";
277 break;
278 case Event::sioPowerGoodWatchdogTimerExpired:
279 return "SIO power good watchdog timer expired";
280 break;
281 case Event::gracefulPowerOffTimerExpired:
282 return "graceful power-off timer expired";
283 break;
284 case Event::powerOnRequest:
285 return "power-on request";
286 break;
287 case Event::powerOffRequest:
288 return "power-off request";
289 break;
290 case Event::powerCycleRequest:
291 return "power-cycle request";
292 break;
293 case Event::resetRequest:
294 return "reset request";
295 break;
296 case Event::gracefulPowerOffRequest:
297 return "graceful power-off request";
298 break;
299 case Event::gracefulPowerCycleRequest:
300 return "graceful power-cycle request";
301 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700302 case Event::warmResetDetected:
303 return "warm reset detected";
304 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700305 default:
306 return "unknown event: " + std::to_string(static_cast<int>(event));
307 break;
308 }
309}
310static void logEvent(const std::string_view stateHandler, const Event event)
311{
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700312 std::string logMsg{stateHandler};
313 logMsg += ": " + getEventName(event) + " event received";
314 phosphor::logging::log<phosphor::logging::level::INFO>(
315 logMsg.c_str(),
316 phosphor::logging::entry("EVENT=%s", getEventName(event).c_str()));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700317}
318
319// Power state handlers
320static void powerStateOn(const Event event);
321static void powerStateWaitForPSPowerOK(const Event event);
322static void powerStateWaitForSIOPowerGood(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700323static void powerStateOff(const Event event);
324static void powerStateTransitionToOff(const Event event);
325static void powerStateGracefulTransitionToOff(const Event event);
326static void powerStateCycleOff(const Event event);
327static void powerStateTransitionToCycleOff(const Event event);
328static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700329static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700330
331static std::function<void(const Event)> getPowerStateHandler(PowerState state)
332{
333 switch (state)
334 {
335 case PowerState::on:
336 return powerStateOn;
337 break;
338 case PowerState::waitForPSPowerOK:
339 return powerStateWaitForPSPowerOK;
340 break;
341 case PowerState::waitForSIOPowerGood:
342 return powerStateWaitForSIOPowerGood;
343 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700344 case PowerState::off:
345 return powerStateOff;
346 break;
347 case PowerState::transitionToOff:
348 return powerStateTransitionToOff;
349 break;
350 case PowerState::gracefulTransitionToOff:
351 return powerStateGracefulTransitionToOff;
352 break;
353 case PowerState::cycleOff:
354 return powerStateCycleOff;
355 break;
356 case PowerState::transitionToCycleOff:
357 return powerStateTransitionToCycleOff;
358 break;
359 case PowerState::gracefulTransitionToCycleOff:
360 return powerStateGracefulTransitionToCycleOff;
361 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700362 case PowerState::checkForWarmReset:
363 return powerStateCheckForWarmReset;
364 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700365 default:
366 return std::function<void(const Event)>{};
367 break;
368 }
369};
370
371static void sendPowerControlEvent(const Event event)
372{
373 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
374 if (handler == nullptr)
375 {
376 std::cerr << "Failed to find handler for power state: "
377 << static_cast<int>(powerState) << "\n";
378 return;
379 }
380 handler(event);
381}
382
383static uint64_t getCurrentTimeMs()
384{
385 struct timespec time = {};
386
387 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
388 {
389 return 0;
390 }
391 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
392 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
393
394 return currentTimeMs;
395}
396
397static constexpr std::string_view getHostState(const PowerState state)
398{
399 switch (state)
400 {
401 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700402 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700403 case PowerState::gracefulTransitionToCycleOff:
404 return "xyz.openbmc_project.State.Host.HostState.Running";
405 break;
406 case PowerState::waitForPSPowerOK:
407 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700408 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700409 case PowerState::transitionToOff:
410 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700411 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700412 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700413 return "xyz.openbmc_project.State.Host.HostState.Off";
414 break;
415 default:
416 return "";
417 break;
418 }
419};
420static constexpr std::string_view getChassisState(const PowerState state)
421{
422 switch (state)
423 {
424 case PowerState::on:
425 case PowerState::transitionToOff:
426 case PowerState::gracefulTransitionToOff:
427 case PowerState::transitionToCycleOff:
428 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700429 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700430 return "xyz.openbmc_project.State.Chassis.PowerState.On";
431 break;
432 case PowerState::waitForPSPowerOK:
433 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700434 case PowerState::off:
435 case PowerState::cycleOff:
436 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
437 break;
438 default:
439 return "";
440 break;
441 }
442};
443static void savePowerState(const PowerState state)
444{
445 powerStateSaveTimer.expires_after(
446 std::chrono::milliseconds(powerOffSaveTimeMs));
447 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
448 if (ec)
449 {
450 // operation_aborted is expected if timer is canceled before
451 // completion.
452 if (ec != boost::asio::error::operation_aborted)
453 {
454 std::cerr << "Power-state save async_wait failed: "
455 << ec.message() << "\n";
456 }
457 return;
458 }
459 std::ofstream powerStateStream(powerControlDir / powerStateFile);
460 powerStateStream << getChassisState(state);
461 });
462}
463static void setPowerState(const PowerState state)
464{
465 powerState = state;
466 logStateTransition(state);
467
468 hostIface->set_property("CurrentHostState",
469 std::string(getHostState(powerState)));
470
471 chassisIface->set_property("CurrentPowerState",
472 std::string(getChassisState(powerState)));
473 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
474
475 // Save the power state for the restore policy
476 savePowerState(state);
477}
478
479enum class RestartCause
480{
481 command,
482 resetButton,
483 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700484 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700485 powerPolicyOn,
486 powerPolicyRestore,
487 softReset,
488};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700489static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700490static std::string getRestartCause(RestartCause cause)
491{
492 switch (cause)
493 {
494 case RestartCause::command:
495 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
496 break;
497 case RestartCause::resetButton:
498 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
499 break;
500 case RestartCause::powerButton:
501 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
502 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700503 case RestartCause::watchdog:
504 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
505 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700506 case RestartCause::powerPolicyOn:
507 return "xyz.openbmc_project.State.Host.RestartCause."
508 "PowerPolicyAlwaysOn";
509 break;
510 case RestartCause::powerPolicyRestore:
511 return "xyz.openbmc_project.State.Host.RestartCause."
512 "PowerPolicyPreviousState";
513 break;
514 case RestartCause::softReset:
515 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
516 break;
517 default:
518 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
519 break;
520 }
521}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700522static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700523{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700524 // Add this to the set of causes for this restart
525 causeSet.insert(cause);
526}
527static void clearRestartCause()
528{
529 // Clear the set for the next restart
530 causeSet.clear();
531}
532static void setRestartCauseProperty(const std::string& cause)
533{
534 std::cerr << "RestartCause set to " << cause << "\n";
535 restartCauseIface->set_property("RestartCause", cause);
536}
Rashmi RV89f61312020-01-22 15:41:50 +0530537
538static void resetACBootProperty()
539{
540 if ((causeSet.contains(RestartCause::command)) ||
541 (causeSet.contains(RestartCause::softReset)))
542 {
543 conn->async_method_call(
544 [](boost::system::error_code ec) {
545 if (ec)
546 {
547 std::cerr << "failed to reset ACBoot property\n";
548 }
549 },
550 "xyz.openbmc_project.Settings",
551 "/xyz/openbmc_project/control/host0/ac_boot",
552 "org.freedesktop.DBus.Properties", "Set",
553 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
554 std::variant<std::string>{"False"});
555 }
556}
557
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700558static void setRestartCause()
559{
560 // Determine the actual restart cause based on the set of causes
561 std::string restartCause =
562 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
563 if (causeSet.contains(RestartCause::watchdog))
564 {
565 restartCause = getRestartCause(RestartCause::watchdog);
566 }
567 else if (causeSet.contains(RestartCause::command))
568 {
569 restartCause = getRestartCause(RestartCause::command);
570 }
571 else if (causeSet.contains(RestartCause::resetButton))
572 {
573 restartCause = getRestartCause(RestartCause::resetButton);
574 }
575 else if (causeSet.contains(RestartCause::powerButton))
576 {
577 restartCause = getRestartCause(RestartCause::powerButton);
578 }
579 else if (causeSet.contains(RestartCause::powerPolicyOn))
580 {
581 restartCause = getRestartCause(RestartCause::powerPolicyOn);
582 }
583 else if (causeSet.contains(RestartCause::powerPolicyRestore))
584 {
585 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
586 }
587 else if (causeSet.contains(RestartCause::softReset))
588 {
589 restartCause = getRestartCause(RestartCause::softReset);
590 }
591
592 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700593}
594
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700595static void systemPowerGoodFailedLog()
596{
597 sd_journal_send(
598 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
599 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
600 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
601 sioPowerGoodWatchdogTimeMs, NULL);
602}
603
604static void psPowerOKFailedLog()
605{
606 sd_journal_send(
607 "MESSAGE=PowerControl: power supply power good failed to assert",
608 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
609 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
610 psPowerOKWatchdogTimeMs, NULL);
611}
612
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700613static void powerRestorePolicyLog()
614{
615 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
616 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
617 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
618}
619
620static void powerButtonPressLog()
621{
622 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
623 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
624 "OpenBMC.0.1.PowerButtonPressed", NULL);
625}
626
627static void resetButtonPressLog()
628{
629 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
630 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
631 "OpenBMC.0.1.ResetButtonPressed", NULL);
632}
633
634static void nmiButtonPressLog()
635{
636 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
637 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
638 "OpenBMC.0.1.NMIButtonPressed", NULL);
639}
640
641static void nmiDiagIntLog()
642{
643 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
644 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
645 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
646}
647
648static int initializePowerStateStorage()
649{
650 // create the power control directory if it doesn't exist
651 std::error_code ec;
652 if (!(std::filesystem::create_directories(powerControlDir, ec)))
653 {
654 if (ec.value() != 0)
655 {
656 std::cerr << "failed to create " << powerControlDir << ": "
657 << ec.message() << "\n";
658 return -1;
659 }
660 }
661 // Create the power state file if it doesn't exist
662 if (!std::filesystem::exists(powerControlDir / powerStateFile))
663 {
664 std::ofstream powerStateStream(powerControlDir / powerStateFile);
665 powerStateStream << getChassisState(powerState);
666 }
667 return 0;
668}
669
670static bool wasPowerDropped()
671{
672 std::ifstream powerStateStream(powerControlDir / powerStateFile);
673 if (!powerStateStream.is_open())
674 {
675 std::cerr << "Failed to open power state file\n";
676 return false;
677 }
678
679 std::string state;
680 std::getline(powerStateStream, state);
681 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
682}
683
684static void invokePowerRestorePolicy(const std::string& policy)
685{
686 // Async events may call this twice, but we only want to run once
687 static bool policyInvoked = false;
688 if (policyInvoked)
689 {
690 return;
691 }
692 policyInvoked = true;
693
694 std::cerr << "Power restore delay expired, invoking " << policy << "\n";
695 if (policy ==
696 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
697 {
698 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700699 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700700 }
701 else if (policy == "xyz.openbmc_project.Control.Power.RestorePolicy."
702 "Policy.Restore")
703 {
704 if (wasPowerDropped())
705 {
706 std::cerr << "Power was dropped, restoring Host On state\n";
707 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700708 setRestartCauseProperty(
709 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700710 }
711 else
712 {
713 std::cerr << "No power drop, restoring Host Off state\n";
714 }
715 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -0700716 // We're done with the previous power state for the restore policy, so store
717 // the current state
718 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700719}
720
721static void powerRestorePolicyDelay(int delay)
722{
723 // Async events may call this twice, but we only want to run once
724 static bool delayStarted = false;
725 if (delayStarted)
726 {
727 return;
728 }
729 delayStarted = true;
730 // Calculate the delay from now to meet the requested delay
731 // Subtract the approximate uboot time
732 static constexpr const int ubootSeconds = 20;
733 delay -= ubootSeconds;
734 // Subtract the time since boot
735 struct sysinfo info = {};
736 if (sysinfo(&info) == 0)
737 {
738 delay -= info.uptime;
739 }
740 // 0 is the minimum delay
741 delay = std::max(delay, 0);
742
743 static boost::asio::steady_timer powerRestorePolicyTimer(io);
744 powerRestorePolicyTimer.expires_after(std::chrono::seconds(delay));
745 std::cerr << "Power restore delay of " << delay << " seconds started\n";
746 powerRestorePolicyTimer.async_wait([](const boost::system::error_code ec) {
747 if (ec)
748 {
749 // operation_aborted is expected if timer is canceled before
750 // completion.
751 if (ec != boost::asio::error::operation_aborted)
752 {
753 std::cerr << "power restore policy async_wait failed: "
754 << ec.message() << "\n";
755 }
756 return;
757 }
758 // Get Power Restore Policy
759 // In case PowerRestorePolicy is not available, set a match for it
760 static std::unique_ptr<sdbusplus::bus::match::match>
761 powerRestorePolicyMatch = std::make_unique<
762 sdbusplus::bus::match::match>(
763 *conn,
764 "type='signal',interface='org.freedesktop.DBus.Properties',"
765 "member='PropertiesChanged',arg0namespace='xyz.openbmc_"
766 "project.Control.Power.RestorePolicy'",
767 [](sdbusplus::message::message& msg) {
768 std::string interfaceName;
769 boost::container::flat_map<std::string,
770 std::variant<std::string>>
771 propertiesChanged;
772 std::string policy;
773 try
774 {
775 msg.read(interfaceName, propertiesChanged);
776 policy = std::get<std::string>(
777 propertiesChanged.begin()->second);
778 }
779 catch (std::exception& e)
780 {
781 std::cerr
782 << "Unable to read power restore policy value\n";
783 powerRestorePolicyMatch.reset();
784 return;
785 }
786 invokePowerRestorePolicy(policy);
787 powerRestorePolicyMatch.reset();
788 });
789
790 // Check if it's already on DBus
791 conn->async_method_call(
792 [](boost::system::error_code ec,
793 const std::variant<std::string>& policyProperty) {
794 if (ec)
795 {
796 return;
797 }
798 powerRestorePolicyMatch.reset();
799 const std::string* policy =
800 std::get_if<std::string>(&policyProperty);
801 if (policy == nullptr)
802 {
803 std::cerr << "Unable to read power restore policy value\n";
804 return;
805 }
806 invokePowerRestorePolicy(*policy);
807 },
808 "xyz.openbmc_project.Settings",
809 "/xyz/openbmc_project/control/host0/power_restore_policy",
810 "org.freedesktop.DBus.Properties", "Get",
811 "xyz.openbmc_project.Control.Power.RestorePolicy",
812 "PowerRestorePolicy");
813 });
814}
815
816static void powerRestorePolicyStart()
817{
818 std::cerr << "Power restore policy started\n";
819 powerRestorePolicyLog();
820
821 // Get the desired delay time
822 // In case PowerRestoreDelay is not available, set a match for it
823 static std::unique_ptr<sdbusplus::bus::match::match>
824 powerRestoreDelayMatch = std::make_unique<sdbusplus::bus::match::match>(
825 *conn,
826 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
827 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Control."
828 "Power.RestoreDelay'",
829 [](sdbusplus::message::message& msg) {
830 std::string interfaceName;
831 boost::container::flat_map<std::string, std::variant<uint16_t>>
832 propertiesChanged;
833 int delay = 0;
834 try
835 {
836 msg.read(interfaceName, propertiesChanged);
837 delay =
838 std::get<uint16_t>(propertiesChanged.begin()->second);
839 }
840 catch (std::exception& e)
841 {
842 std::cerr << "Unable to read power restore delay value\n";
843 powerRestoreDelayMatch.reset();
844 return;
845 }
846 powerRestorePolicyDelay(delay);
847 powerRestoreDelayMatch.reset();
848 });
849
850 // Check if it's already on DBus
851 conn->async_method_call(
852 [](boost::system::error_code ec,
853 const std::variant<uint16_t>& delayProperty) {
854 if (ec)
855 {
856 return;
857 }
858 powerRestoreDelayMatch.reset();
859 const uint16_t* delay = std::get_if<uint16_t>(&delayProperty);
860 if (delay == nullptr)
861 {
862 std::cerr << "Unable to read power restore delay value\n";
863 return;
864 }
865 powerRestorePolicyDelay(*delay);
866 },
867 "xyz.openbmc_project.Settings",
868 "/xyz/openbmc_project/control/power_restore_delay",
869 "org.freedesktop.DBus.Properties", "Get",
870 "xyz.openbmc_project.Control.Power.RestoreDelay", "PowerRestoreDelay");
871}
872
873static void powerRestorePolicyCheck()
874{
875 // In case ACBoot is not available, set a match for it
876 static std::unique_ptr<sdbusplus::bus::match::match> acBootMatch =
877 std::make_unique<sdbusplus::bus::match::match>(
878 *conn,
879 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
880 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Common."
881 "ACBoot'",
882 [](sdbusplus::message::message& msg) {
883 std::string interfaceName;
884 boost::container::flat_map<std::string,
885 std::variant<std::string>>
886 propertiesChanged;
887 std::string acBoot;
888 try
889 {
890 msg.read(interfaceName, propertiesChanged);
891 acBoot = std::get<std::string>(
892 propertiesChanged.begin()->second);
893 }
894 catch (std::exception& e)
895 {
896 std::cerr << "Unable to read AC Boot status\n";
897 acBootMatch.reset();
898 return;
899 }
900 if (acBoot == "Unknown")
901 {
902 return;
903 }
904 if (acBoot == "True")
905 {
906 // Start the Power Restore policy
907 powerRestorePolicyStart();
908 }
909 acBootMatch.reset();
910 });
911
912 // Check if it's already on DBus
913 conn->async_method_call(
914 [](boost::system::error_code ec,
915 const std::variant<std::string>& acBootProperty) {
916 if (ec)
917 {
918 return;
919 }
920 const std::string* acBoot =
921 std::get_if<std::string>(&acBootProperty);
922 if (acBoot == nullptr)
923 {
924 std::cerr << "Unable to read AC Boot status\n";
925 return;
926 }
927 if (*acBoot == "Unknown")
928 {
929 return;
930 }
931 if (*acBoot == "True")
932 {
933 // Start the Power Restore policy
934 powerRestorePolicyStart();
935 }
936 acBootMatch.reset();
937 },
938 "xyz.openbmc_project.Settings",
939 "/xyz/openbmc_project/control/host0/ac_boot",
940 "org.freedesktop.DBus.Properties", "Get",
941 "xyz.openbmc_project.Common.ACBoot", "ACBoot");
942}
943
944static bool requestGPIOEvents(
945 const std::string& name, const std::function<void()>& handler,
946 gpiod::line& gpioLine,
947 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
948{
949 // Find the GPIO line
950 gpioLine = gpiod::find_line(name);
951 if (!gpioLine)
952 {
953 std::cerr << "Failed to find the " << name << " line\n";
954 return false;
955 }
956
957 try
958 {
959 gpioLine.request(
960 {"power-control", gpiod::line_request::EVENT_BOTH_EDGES});
961 }
962 catch (std::exception&)
963 {
964 std::cerr << "Failed to request events for " << name << "\n";
965 return false;
966 }
967
968 int gpioLineFd = gpioLine.event_get_fd();
969 if (gpioLineFd < 0)
970 {
971 std::cerr << "Failed to get " << name << " fd\n";
972 return false;
973 }
974
975 gpioEventDescriptor.assign(gpioLineFd);
976
977 gpioEventDescriptor.async_wait(
978 boost::asio::posix::stream_descriptor::wait_read,
979 [&name, handler](const boost::system::error_code ec) {
980 if (ec)
981 {
982 std::cerr << name << " fd handler error: " << ec.message()
983 << "\n";
984 // TODO: throw here to force power-control to restart?
985 return;
986 }
987 handler();
988 });
989 return true;
990}
991
992static bool setGPIOOutput(const std::string& name, const int value,
993 gpiod::line& gpioLine)
994{
995 // Find the GPIO line
996 gpioLine = gpiod::find_line(name);
997 if (!gpioLine)
998 {
999 std::cerr << "Failed to find the " << name << " line.\n";
1000 return false;
1001 }
1002
1003 // Request GPIO output to specified value
1004 try
1005 {
1006 gpioLine.request({__FUNCTION__, gpiod::line_request::DIRECTION_OUTPUT},
1007 value);
1008 }
1009 catch (std::exception&)
1010 {
1011 std::cerr << "Failed to request " << name << " output\n";
1012 return false;
1013 }
1014
1015 std::cerr << name << " set to " << std::to_string(value) << "\n";
1016 return true;
1017}
1018
1019static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1020 const std::string& name, const int value,
1021 const int durationMs)
1022{
1023 // Set the masked GPIO line to the specified value
1024 maskedGPIOLine.set_value(value);
1025 std::cerr << name << " set to " << std::to_string(value) << "\n";
1026 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
1027 gpioAssertTimer.async_wait(
1028 [maskedGPIOLine, value, name](const boost::system::error_code ec) {
1029 // Set the masked GPIO line back to the opposite value
1030 maskedGPIOLine.set_value(!value);
1031 std::cerr << name << " released\n";
1032 if (ec)
1033 {
1034 // operation_aborted is expected if timer is canceled before
1035 // completion.
1036 if (ec != boost::asio::error::operation_aborted)
1037 {
1038 std::cerr << name << " async_wait failed: " + ec.message()
1039 << "\n";
1040 }
1041 }
1042 });
1043 return 0;
1044}
1045
1046static int setGPIOOutputForMs(const std::string& name, const int value,
1047 const int durationMs)
1048{
1049 // If the requested GPIO is masked, use the mask line to set the output
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001050 if (powerButtonMask && name == power_control::powerOutName)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001051 {
1052 return setMaskedGPIOOutputForMs(powerButtonMask, name, value,
1053 durationMs);
1054 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001055 if (resetButtonMask && name == power_control::resetOutName)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001056 {
1057 return setMaskedGPIOOutputForMs(resetButtonMask, name, value,
1058 durationMs);
1059 }
1060
1061 // No mask set, so request and set the GPIO normally
1062 gpiod::line gpioLine;
1063 if (!setGPIOOutput(name, value, gpioLine))
1064 {
1065 return -1;
1066 }
1067 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
1068 gpioAssertTimer.async_wait(
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001069 [gpioLine, value, name](const boost::system::error_code ec) {
1070 // Set the GPIO line back to the opposite value
1071 gpioLine.set_value(!value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001072 std::cerr << name << " released\n";
1073 if (ec)
1074 {
1075 // operation_aborted is expected if timer is canceled before
1076 // completion.
1077 if (ec != boost::asio::error::operation_aborted)
1078 {
1079 std::cerr << name << " async_wait failed: " << ec.message()
1080 << "\n";
1081 }
1082 }
1083 });
1084 return 0;
1085}
1086
1087static void powerOn()
1088{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001089 setGPIOOutputForMs(power_control::powerOutName, 0, powerPulseTimeMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001090}
1091
1092static void gracefulPowerOff()
1093{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001094 setGPIOOutputForMs(power_control::powerOutName, 0, powerPulseTimeMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001095}
1096
1097static void forcePowerOff()
1098{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001099 if (setGPIOOutputForMs(power_control::powerOutName, 0,
1100 forceOffPulseTimeMs) < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001101 {
1102 return;
1103 }
1104
1105 // If the force off timer expires, then the PCH power-button override
1106 // failed, so attempt the Unconditional Powerdown SMBus command.
1107 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1108 if (ec)
1109 {
1110 // operation_aborted is expected if timer is canceled before
1111 // completion.
1112 if (ec != boost::asio::error::operation_aborted)
1113 {
1114 std::cerr << "Force power off async_wait failed: "
1115 << ec.message() << "\n";
1116 }
1117 return;
1118 }
1119 std::cerr << "PCH Power-button override failed. Issuing Unconditional "
1120 "Powerdown SMBus command.\n";
1121 const static constexpr size_t pchDevBusAddress = 3;
1122 const static constexpr size_t pchDevSlaveAddress = 0x44;
1123 const static constexpr size_t pchCmdReg = 0;
1124 const static constexpr size_t pchPowerDownCmd = 0x02;
1125 if (i2cSet(pchDevBusAddress, pchDevSlaveAddress, pchCmdReg,
1126 pchPowerDownCmd) < 0)
1127 {
1128 std::cerr << "Unconditional Powerdown command failed! Not sure "
1129 "what to do now.\n";
1130 }
1131 });
1132}
1133
1134static void reset()
1135{
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07001136 setGPIOOutputForMs(power_control::resetOutName, 0, resetPulseTimeMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001137}
1138
1139static void gracefulPowerOffTimerStart()
1140{
1141 std::cerr << "Graceful power-off timer started\n";
1142 gracefulPowerOffTimer.expires_after(
1143 std::chrono::milliseconds(gracefulPowerOffTimeMs));
1144 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1145 if (ec)
1146 {
1147 // operation_aborted is expected if timer is canceled before
1148 // completion.
1149 if (ec != boost::asio::error::operation_aborted)
1150 {
1151 std::cerr << "Graceful power-off async_wait failed: "
1152 << ec.message() << "\n";
1153 }
1154 std::cerr << "Graceful power-off timer canceled\n";
1155 return;
1156 }
1157 std::cerr << "Graceful power-off timer completed\n";
1158 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1159 });
1160}
1161
1162static void powerCycleTimerStart()
1163{
1164 std::cerr << "Power-cycle timer started\n";
1165 powerCycleTimer.expires_after(std::chrono::milliseconds(powerCycleTimeMs));
1166 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1167 if (ec)
1168 {
1169 // operation_aborted is expected if timer is canceled before
1170 // completion.
1171 if (ec != boost::asio::error::operation_aborted)
1172 {
1173 std::cerr << "Power-cycle async_wait failed: " << ec.message()
1174 << "\n";
1175 }
1176 std::cerr << "Power-cycle timer canceled\n";
1177 return;
1178 }
1179 std::cerr << "Power-cycle timer completed\n";
1180 sendPowerControlEvent(Event::powerCycleTimerExpired);
1181 });
1182}
1183
1184static void psPowerOKWatchdogTimerStart()
1185{
1186 std::cerr << "power supply power OK watchdog timer started\n";
1187 psPowerOKWatchdogTimer.expires_after(
1188 std::chrono::milliseconds(psPowerOKWatchdogTimeMs));
1189 psPowerOKWatchdogTimer.async_wait(
1190 [](const boost::system::error_code ec) {
1191 if (ec)
1192 {
1193 // operation_aborted is expected if timer is canceled before
1194 // completion.
1195 if (ec != boost::asio::error::operation_aborted)
1196 {
1197 std::cerr
1198 << "power supply power OK watchdog async_wait failed: "
1199 << ec.message() << "\n";
1200 }
1201 std::cerr << "power supply power OK watchdog timer canceled\n";
1202 return;
1203 }
1204 std::cerr << "power supply power OK watchdog timer expired\n";
1205 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1206 });
1207}
1208
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001209static void warmResetCheckTimerStart()
1210{
1211 std::cerr << "Warm reset check timer started\n";
1212 warmResetCheckTimer.expires_after(
1213 std::chrono::milliseconds(warmResetCheckTimeMs));
1214 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1215 if (ec)
1216 {
1217 // operation_aborted is expected if timer is canceled before
1218 // completion.
1219 if (ec != boost::asio::error::operation_aborted)
1220 {
1221 std::cerr << "Warm reset check async_wait failed: "
1222 << ec.message() << "\n";
1223 }
1224 std::cerr << "Warm reset check timer canceled\n";
1225 return;
1226 }
1227 std::cerr << "Warm reset check timer completed\n";
1228 sendPowerControlEvent(Event::warmResetDetected);
1229 });
1230}
1231
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001232static void pohCounterTimerStart()
1233{
1234 std::cerr << "POH timer started\n";
1235 // Set the time-out as 1 hour, to align with POH command in ipmid
1236 pohCounterTimer.expires_after(std::chrono::hours(1));
1237 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1238 if (ec)
1239 {
1240 // operation_aborted is expected if timer is canceled before
1241 // completion.
1242 if (ec != boost::asio::error::operation_aborted)
1243 {
1244 std::cerr << "POH timer async_wait failed: " << ec.message()
1245 << "\n";
1246 }
1247 std::cerr << "POH timer canceled\n";
1248 return;
1249 }
1250
1251 if (getHostState(powerState) !=
1252 "xyz.openbmc_project.State.Host.HostState.Running")
1253 {
1254 return;
1255 }
1256
1257 conn->async_method_call(
1258 [](boost::system::error_code ec,
1259 const std::variant<uint32_t>& pohCounterProperty) {
1260 if (ec)
1261 {
1262 std::cerr << "error to get poh counter\n";
1263 return;
1264 }
1265 const uint32_t* pohCounter =
1266 std::get_if<uint32_t>(&pohCounterProperty);
1267 if (pohCounter == nullptr)
1268 {
1269 std::cerr << "unable to read poh counter\n";
1270 return;
1271 }
1272
1273 conn->async_method_call(
1274 [](boost::system::error_code ec) {
1275 if (ec)
1276 {
1277 std::cerr << "failed to set poh counter\n";
1278 }
1279 },
1280 "xyz.openbmc_project.Settings",
1281 "/xyz/openbmc_project/state/chassis0",
1282 "org.freedesktop.DBus.Properties", "Set",
1283 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1284 std::variant<uint32_t>(*pohCounter + 1));
1285 },
1286 "xyz.openbmc_project.Settings",
1287 "/xyz/openbmc_project/state/chassis0",
1288 "org.freedesktop.DBus.Properties", "Get",
1289 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1290
1291 pohCounterTimerStart();
1292 });
1293}
1294
1295static void currentHostStateMonitor()
1296{
Yong Li8d660212019-12-27 10:18:10 +08001297 if (getHostState(powerState) ==
1298 "xyz.openbmc_project.State.Host.HostState.Running")
1299 {
1300 pohCounterTimerStart();
1301 // Clear the restart cause set for the next restart
1302 clearRestartCause();
1303 }
1304 else
1305 {
1306 pohCounterTimer.cancel();
1307 // Set the restart cause set for this restart
1308 setRestartCause();
1309 }
1310
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001311 static auto match = sdbusplus::bus::match::match(
1312 *conn,
1313 "type='signal',member='PropertiesChanged', "
1314 "interface='org.freedesktop.DBus.Properties', "
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001315 "arg0='xyz.openbmc_project.State.Host'",
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001316 [](sdbusplus::message::message& message) {
1317 std::string intfName;
1318 std::map<std::string, std::variant<std::string>> properties;
1319
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001320 try
1321 {
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001322 message.read(intfName, properties);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001323 }
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001324 catch (std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001325 {
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001326 std::cerr << "Unable to read host state\n";
1327 return;
1328 }
1329 if (properties.empty())
1330 {
1331 std::cerr << "ERROR: Empty PropertiesChanged signal received\n";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001332 return;
1333 }
1334
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001335 // We only want to check for CurrentHostState
1336 if (properties.begin()->first != "CurrentHostState")
1337 {
1338 return;
1339 }
1340 std::string* currentHostState =
1341 std::get_if<std::string>(&(properties.begin()->second));
1342 if (currentHostState == nullptr)
1343 {
1344 std::cerr << properties.begin()->first << " property invalid\n";
1345 return;
1346 }
1347
1348 if (*currentHostState ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001349 "xyz.openbmc_project.State.Host.HostState.Running")
1350 {
1351 pohCounterTimerStart();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001352 // Clear the restart cause set for the next restart
1353 clearRestartCause();
Yong Li8d660212019-12-27 10:18:10 +08001354 sd_journal_send("MESSAGE=Host system DC power is on",
1355 "PRIORITY=%i", LOG_INFO,
1356 "REDFISH_MESSAGE_ID=%s",
1357 "OpenBMC.0.1.DCPowerOn", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001358 }
1359 else
1360 {
1361 pohCounterTimer.cancel();
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301362 // POST_COMPLETE GPIO event is not working in some platforms
1363 // when power state is changed to OFF. This resulted in
1364 // 'OperatingSystemState' to stay at 'Standby', even though
1365 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1366 // if HostState is trurned to OFF.
1367 osIface->set_property("OperatingSystemState",
1368 std::string("Inactive"));
1369
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001370 // Set the restart cause set for this restart
1371 setRestartCause();
Rashmi RV89f61312020-01-22 15:41:50 +05301372 resetACBootProperty();
Yong Li8d660212019-12-27 10:18:10 +08001373 sd_journal_send("MESSAGE=Host system DC power is off",
1374 "PRIORITY=%i", LOG_INFO,
1375 "REDFISH_MESSAGE_ID=%s",
1376 "OpenBMC.0.1.DCPowerOff", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001377 }
1378 });
1379}
1380
1381static void sioPowerGoodWatchdogTimerStart()
1382{
1383 std::cerr << "SIO power good watchdog timer started\n";
1384 sioPowerGoodWatchdogTimer.expires_after(
1385 std::chrono::milliseconds(sioPowerGoodWatchdogTimeMs));
1386 sioPowerGoodWatchdogTimer.async_wait(
1387 [](const boost::system::error_code ec) {
1388 if (ec)
1389 {
1390 // operation_aborted is expected if timer is canceled before
1391 // completion.
1392 if (ec != boost::asio::error::operation_aborted)
1393 {
1394 std::cerr << "SIO power good watchdog async_wait failed: "
1395 << ec.message() << "\n";
1396 }
1397 std::cerr << "SIO power good watchdog timer canceled\n";
1398 return;
1399 }
1400 std::cerr << "SIO power good watchdog timer completed\n";
1401 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1402 });
1403}
1404
1405static void powerStateOn(const Event event)
1406{
1407 logEvent(__FUNCTION__, event);
1408 switch (event)
1409 {
1410 case Event::psPowerOKDeAssert:
1411 setPowerState(PowerState::off);
1412 // DC power is unexpectedly lost, beep
1413 beep(beepPowerFail);
1414 break;
1415 case Event::sioS5Assert:
1416 setPowerState(PowerState::transitionToOff);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001417 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001418 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001419 case Event::postCompleteDeAssert:
1420 setPowerState(PowerState::checkForWarmReset);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001421 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001422 warmResetCheckTimerStart();
1423 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001424 case Event::powerButtonPressed:
1425 setPowerState(PowerState::gracefulTransitionToOff);
1426 gracefulPowerOffTimerStart();
1427 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001428 case Event::resetButtonPressed:
1429 setPowerState(PowerState::checkForWarmReset);
1430 warmResetCheckTimerStart();
1431 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001432 case Event::powerOffRequest:
1433 setPowerState(PowerState::transitionToOff);
1434 forcePowerOff();
1435 break;
1436 case Event::gracefulPowerOffRequest:
1437 setPowerState(PowerState::gracefulTransitionToOff);
1438 gracefulPowerOffTimerStart();
1439 gracefulPowerOff();
1440 break;
1441 case Event::powerCycleRequest:
1442 setPowerState(PowerState::transitionToCycleOff);
1443 forcePowerOff();
1444 break;
1445 case Event::gracefulPowerCycleRequest:
1446 setPowerState(PowerState::gracefulTransitionToCycleOff);
1447 gracefulPowerOffTimerStart();
1448 gracefulPowerOff();
1449 break;
1450 case Event::resetRequest:
1451 reset();
1452 break;
1453 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001454 phosphor::logging::log<phosphor::logging::level::INFO>(
1455 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001456 break;
1457 }
1458}
1459
1460static void powerStateWaitForPSPowerOK(const Event event)
1461{
1462 logEvent(__FUNCTION__, event);
1463 switch (event)
1464 {
1465 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301466 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001467 // Cancel any GPIO assertions held during the transition
1468 gpioAssertTimer.cancel();
1469 psPowerOKWatchdogTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301470 if (sioEnabled == true)
1471 {
1472 sioPowerGoodWatchdogTimerStart();
1473 setPowerState(PowerState::waitForSIOPowerGood);
1474 }
1475 else
1476 {
1477 setPowerState(PowerState::on);
1478 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001479 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301480 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001481 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001482 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001483 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001484 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001485 case Event::sioPowerGoodAssert:
1486 psPowerOKWatchdogTimer.cancel();
1487 setPowerState(PowerState::on);
1488 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001489 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001490 phosphor::logging::log<phosphor::logging::level::INFO>(
1491 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001492 break;
1493 }
1494}
1495
1496static void powerStateWaitForSIOPowerGood(const Event event)
1497{
1498 logEvent(__FUNCTION__, event);
1499 switch (event)
1500 {
1501 case Event::sioPowerGoodAssert:
1502 sioPowerGoodWatchdogTimer.cancel();
1503 setPowerState(PowerState::on);
1504 break;
1505 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001506 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001507 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001508 break;
1509 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001510 phosphor::logging::log<phosphor::logging::level::INFO>(
1511 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001512 break;
1513 }
1514}
1515
1516static void powerStateOff(const Event event)
1517{
1518 logEvent(__FUNCTION__, event);
1519 switch (event)
1520 {
1521 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301522 {
1523 if (sioEnabled == true)
1524 {
1525 setPowerState(PowerState::waitForSIOPowerGood);
1526 }
1527 else
1528 {
1529 setPowerState(PowerState::on);
1530 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001531 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301532 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001533 case Event::sioS5DeAssert:
1534 setPowerState(PowerState::waitForPSPowerOK);
1535 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001536 case Event::sioPowerGoodAssert:
1537 setPowerState(PowerState::on);
1538 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001539 case Event::powerButtonPressed:
1540 psPowerOKWatchdogTimerStart();
1541 setPowerState(PowerState::waitForPSPowerOK);
1542 break;
1543 case Event::powerOnRequest:
1544 psPowerOKWatchdogTimerStart();
1545 setPowerState(PowerState::waitForPSPowerOK);
1546 powerOn();
1547 break;
1548 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001549 phosphor::logging::log<phosphor::logging::level::INFO>(
1550 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001551 break;
1552 }
1553}
1554
1555static void powerStateTransitionToOff(const Event event)
1556{
1557 logEvent(__FUNCTION__, event);
1558 switch (event)
1559 {
1560 case Event::psPowerOKDeAssert:
1561 // Cancel any GPIO assertions held during the transition
1562 gpioAssertTimer.cancel();
1563 setPowerState(PowerState::off);
1564 break;
1565 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001566 phosphor::logging::log<phosphor::logging::level::INFO>(
1567 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001568 break;
1569 }
1570}
1571
1572static void powerStateGracefulTransitionToOff(const Event event)
1573{
1574 logEvent(__FUNCTION__, event);
1575 switch (event)
1576 {
1577 case Event::psPowerOKDeAssert:
1578 gracefulPowerOffTimer.cancel();
1579 setPowerState(PowerState::off);
1580 break;
1581 case Event::gracefulPowerOffTimerExpired:
1582 setPowerState(PowerState::on);
1583 break;
1584 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001585 phosphor::logging::log<phosphor::logging::level::INFO>(
1586 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001587 break;
1588 }
1589}
1590
1591static void powerStateCycleOff(const Event event)
1592{
1593 logEvent(__FUNCTION__, event);
1594 switch (event)
1595 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001596 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301597 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001598 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301599 if (sioEnabled == true)
1600 {
1601 setPowerState(PowerState::waitForSIOPowerGood);
1602 }
1603 else
1604 {
1605 setPowerState(PowerState::on);
1606 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001607 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301608 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001609 case Event::sioS5DeAssert:
1610 powerCycleTimer.cancel();
1611 setPowerState(PowerState::waitForPSPowerOK);
1612 break;
1613 case Event::powerButtonPressed:
1614 powerCycleTimer.cancel();
1615 psPowerOKWatchdogTimerStart();
1616 setPowerState(PowerState::waitForPSPowerOK);
1617 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001618 case Event::powerCycleTimerExpired:
1619 psPowerOKWatchdogTimerStart();
1620 setPowerState(PowerState::waitForPSPowerOK);
1621 powerOn();
1622 break;
1623 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001624 phosphor::logging::log<phosphor::logging::level::INFO>(
1625 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001626 break;
1627 }
1628}
1629
1630static void powerStateTransitionToCycleOff(const Event event)
1631{
1632 logEvent(__FUNCTION__, event);
1633 switch (event)
1634 {
1635 case Event::psPowerOKDeAssert:
1636 // Cancel any GPIO assertions held during the transition
1637 gpioAssertTimer.cancel();
1638 setPowerState(PowerState::cycleOff);
1639 powerCycleTimerStart();
1640 break;
1641 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001642 phosphor::logging::log<phosphor::logging::level::INFO>(
1643 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001644 break;
1645 }
1646}
1647
1648static void powerStateGracefulTransitionToCycleOff(const Event event)
1649{
1650 logEvent(__FUNCTION__, event);
1651 switch (event)
1652 {
1653 case Event::psPowerOKDeAssert:
1654 gracefulPowerOffTimer.cancel();
1655 setPowerState(PowerState::cycleOff);
1656 powerCycleTimerStart();
1657 break;
1658 case Event::gracefulPowerOffTimerExpired:
1659 setPowerState(PowerState::on);
1660 break;
1661 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001662 phosphor::logging::log<phosphor::logging::level::INFO>(
1663 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001664 break;
1665 }
1666}
1667
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001668static void powerStateCheckForWarmReset(const Event event)
1669{
1670 logEvent(__FUNCTION__, event);
1671 switch (event)
1672 {
1673 case Event::sioS5Assert:
1674 warmResetCheckTimer.cancel();
1675 setPowerState(PowerState::transitionToOff);
1676 break;
1677 case Event::warmResetDetected:
1678 setPowerState(PowerState::on);
1679 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001680 case Event::psPowerOKDeAssert:
1681 warmResetCheckTimer.cancel();
1682 setPowerState(PowerState::off);
1683 // DC power is unexpectedly lost, beep
1684 beep(beepPowerFail);
1685 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001686 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001687 phosphor::logging::log<phosphor::logging::level::INFO>(
1688 "No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001689 break;
1690 }
1691}
1692
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001693static void psPowerOKHandler()
1694{
1695 gpiod::line_event gpioLineEvent = psPowerOKLine.event_read();
1696
1697 Event powerControlEvent =
1698 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
1699 ? Event::psPowerOKAssert
1700 : Event::psPowerOKDeAssert;
1701
1702 sendPowerControlEvent(powerControlEvent);
1703 psPowerOKEvent.async_wait(
1704 boost::asio::posix::stream_descriptor::wait_read,
1705 [](const boost::system::error_code ec) {
1706 if (ec)
1707 {
1708 std::cerr << "power supply power OK handler error: "
1709 << ec.message() << "\n";
1710 return;
1711 }
1712 psPowerOKHandler();
1713 });
1714}
1715
1716static void sioPowerGoodHandler()
1717{
1718 gpiod::line_event gpioLineEvent = sioPowerGoodLine.event_read();
1719
1720 Event powerControlEvent =
1721 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
1722 ? Event::sioPowerGoodAssert
1723 : Event::sioPowerGoodDeAssert;
1724
1725 sendPowerControlEvent(powerControlEvent);
1726 sioPowerGoodEvent.async_wait(
1727 boost::asio::posix::stream_descriptor::wait_read,
1728 [](const boost::system::error_code ec) {
1729 if (ec)
1730 {
1731 std::cerr << "SIO power good handler error: " << ec.message()
1732 << "\n";
1733 return;
1734 }
1735 sioPowerGoodHandler();
1736 });
1737}
1738
1739static void sioOnControlHandler()
1740{
1741 gpiod::line_event gpioLineEvent = sioOnControlLine.event_read();
1742
1743 bool sioOnControl =
1744 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE;
1745 std::cerr << "SIO_ONCONTROL value changed: " << sioOnControl << "\n";
1746 sioOnControlEvent.async_wait(
1747 boost::asio::posix::stream_descriptor::wait_read,
1748 [](const boost::system::error_code ec) {
1749 if (ec)
1750 {
1751 std::cerr << "SIO ONCONTROL handler error: " << ec.message()
1752 << "\n";
1753 return;
1754 }
1755 sioOnControlHandler();
1756 });
1757}
1758
1759static void sioS5Handler()
1760{
1761 gpiod::line_event gpioLineEvent = sioS5Line.event_read();
1762
1763 Event powerControlEvent =
1764 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE
1765 ? Event::sioS5Assert
1766 : Event::sioS5DeAssert;
1767
1768 sendPowerControlEvent(powerControlEvent);
1769 sioS5Event.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1770 [](const boost::system::error_code ec) {
1771 if (ec)
1772 {
1773 std::cerr << "SIO S5 handler error: "
1774 << ec.message() << "\n";
1775 return;
1776 }
1777 sioS5Handler();
1778 });
1779}
1780
1781static void powerButtonHandler()
1782{
1783 gpiod::line_event gpioLineEvent = powerButtonLine.event_read();
1784
1785 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1786 {
1787 powerButtonPressLog();
1788 powerButtonIface->set_property("ButtonPressed", true);
1789 if (!powerButtonMask)
1790 {
1791 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001792 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001793 }
1794 else
1795 {
1796 std::cerr << "power button press masked\n";
1797 }
1798 }
1799 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
1800 {
1801 powerButtonIface->set_property("ButtonPressed", false);
1802 }
1803 powerButtonEvent.async_wait(
1804 boost::asio::posix::stream_descriptor::wait_read,
1805 [](const boost::system::error_code ec) {
1806 if (ec)
1807 {
1808 std::cerr << "power button handler error: " << ec.message()
1809 << "\n";
1810 return;
1811 }
1812 powerButtonHandler();
1813 });
1814}
1815
1816static void resetButtonHandler()
1817{
1818 gpiod::line_event gpioLineEvent = resetButtonLine.event_read();
1819
1820 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1821 {
1822 resetButtonPressLog();
1823 resetButtonIface->set_property("ButtonPressed", true);
1824 if (!resetButtonMask)
1825 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001826 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001827 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001828 }
1829 else
1830 {
1831 std::cerr << "reset button press masked\n";
1832 }
1833 }
1834 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
1835 {
1836 resetButtonIface->set_property("ButtonPressed", false);
1837 }
1838 resetButtonEvent.async_wait(
1839 boost::asio::posix::stream_descriptor::wait_read,
1840 [](const boost::system::error_code ec) {
1841 if (ec)
1842 {
1843 std::cerr << "reset button handler error: " << ec.message()
1844 << "\n";
1845 return;
1846 }
1847 resetButtonHandler();
1848 });
1849}
1850
Vijay Khemka04175c22020-10-09 14:28:11 -07001851#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07001852static constexpr auto systemdBusname = "org.freedesktop.systemd1";
1853static constexpr auto systemdPath = "/org/freedesktop/systemd1";
1854static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
1855static constexpr auto systemTargetName = "chassis-system-reset.target";
1856
1857void systemReset()
1858{
1859 conn->async_method_call(
1860 [](boost::system::error_code ec) {
1861 if (ec)
1862 {
1863 phosphor::logging::log<phosphor::logging::level::ERR>(
1864 "Failed to call chassis system reset",
1865 phosphor::logging::entry("ERR=%s", ec.message().c_str()));
1866 }
1867 },
1868 systemdBusname, systemdPath, systemdInterface, "StartUnit",
1869 systemTargetName, "replace");
1870}
Vijay Khemka04175c22020-10-09 14:28:11 -07001871#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07001872
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001873static void nmiSetEnablePorperty(bool value)
1874{
1875 conn->async_method_call(
1876 [](boost::system::error_code ec) {
1877 if (ec)
1878 {
1879 std::cerr << "failed to set NMI source\n";
1880 }
1881 },
Chen Yugang303bd582019-11-01 08:45:06 +08001882 "xyz.openbmc_project.Settings",
1883 "/xyz/openbmc_project/Chassis/Control/NMISource",
1884 "org.freedesktop.DBus.Properties", "Set",
1885 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
1886 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001887}
1888
1889static void nmiReset(void)
1890{
1891 static constexpr const uint8_t value = 1;
1892 const static constexpr int nmiOutPulseTimeMs = 200;
1893
1894 std::cerr << "NMI out action \n";
1895 nmiOutLine.set_value(value);
1896 std::cerr << nmiOutName << " set to " << std::to_string(value) << "\n";
1897 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
1898 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1899 // restore the NMI_OUT GPIO line back to the opposite value
1900 nmiOutLine.set_value(!value);
1901 std::cerr << nmiOutName << " released\n";
1902 if (ec)
1903 {
1904 // operation_aborted is expected if timer is canceled before
1905 // completion.
1906 if (ec != boost::asio::error::operation_aborted)
1907 {
1908 std::cerr << nmiOutName << " async_wait failed: " + ec.message()
1909 << "\n";
1910 }
1911 }
1912 });
1913 // log to redfish
1914 nmiDiagIntLog();
1915 std::cerr << "NMI out action completed\n";
1916 // reset Enable Property
1917 nmiSetEnablePorperty(false);
1918}
1919
1920static void nmiSourcePropertyMonitor(void)
1921{
1922 std::cerr << " NMI Source Property Monitor \n";
1923
1924 static std::unique_ptr<sdbusplus::bus::match::match> nmiSourceMatch =
1925 std::make_unique<sdbusplus::bus::match::match>(
1926 *conn,
1927 "type='signal',interface='org.freedesktop.DBus.Properties',"
Chen Yugang303bd582019-11-01 08:45:06 +08001928 "member='PropertiesChanged',arg0namespace='xyz.openbmc_project."
1929 "Chassis.Control."
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001930 "NMISource'",
1931 [](sdbusplus::message::message& msg) {
1932 std::string interfaceName;
1933 boost::container::flat_map<std::string,
1934 std::variant<bool, std::string>>
1935 propertiesChanged;
1936 std::string state;
1937 bool value = true;
1938 try
1939 {
1940 msg.read(interfaceName, propertiesChanged);
1941 if (propertiesChanged.begin()->first == "Enabled")
1942 {
1943 value =
1944 std::get<bool>(propertiesChanged.begin()->second);
1945 std::cerr
1946 << " NMI Enabled propertiesChanged value: " << value
1947 << "\n";
1948 nmiEnabled = value;
1949 if (nmiEnabled)
1950 {
1951 nmiReset();
1952 }
1953 }
1954 }
1955 catch (std::exception& e)
1956 {
1957 std::cerr << "Unable to read NMI source\n";
1958 return;
1959 }
1960 });
1961}
1962
1963static void setNmiSource()
1964{
1965 conn->async_method_call(
1966 [](boost::system::error_code ec) {
1967 if (ec)
1968 {
1969 std::cerr << "failed to set NMI source\n";
1970 }
1971 },
Chen Yugang303bd582019-11-01 08:45:06 +08001972 "xyz.openbmc_project.Settings",
1973 "/xyz/openbmc_project/Chassis/Control/NMISource",
1974 "org.freedesktop.DBus.Properties", "Set",
1975 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
1976 std::variant<std::string>{"xyz.openbmc_project.Chassis.Control."
1977 "NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001978 // set Enable Property
1979 nmiSetEnablePorperty(true);
1980}
1981
1982static void nmiButtonHandler()
1983{
1984 gpiod::line_event gpioLineEvent = nmiButtonLine.event_read();
1985
1986 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
1987 {
1988 nmiButtonPressLog();
1989 nmiButtonIface->set_property("ButtonPressed", true);
1990 if (nmiButtonMasked)
1991 {
1992 std::cerr << "NMI button press masked\n";
1993 }
1994 else
1995 {
1996 setNmiSource();
1997 }
1998 }
1999 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2000 {
2001 nmiButtonIface->set_property("ButtonPressed", false);
2002 }
2003 nmiButtonEvent.async_wait(boost::asio::posix::stream_descriptor::wait_read,
2004 [](const boost::system::error_code ec) {
2005 if (ec)
2006 {
2007 std::cerr << "NMI button handler error: "
2008 << ec.message() << "\n";
2009 return;
2010 }
2011 nmiButtonHandler();
2012 });
2013}
2014
2015static void idButtonHandler()
2016{
2017 gpiod::line_event gpioLineEvent = idButtonLine.event_read();
2018
2019 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2020 {
2021 idButtonIface->set_property("ButtonPressed", true);
2022 }
2023 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2024 {
2025 idButtonIface->set_property("ButtonPressed", false);
2026 }
2027 idButtonEvent.async_wait(boost::asio::posix::stream_descriptor::wait_read,
2028 [](const boost::system::error_code& ec) {
2029 if (ec)
2030 {
2031 std::cerr << "ID button handler error: "
2032 << ec.message() << "\n";
2033 return;
2034 }
2035 idButtonHandler();
2036 });
2037}
2038
2039static void postCompleteHandler()
2040{
2041 gpiod::line_event gpioLineEvent = postCompleteLine.event_read();
2042
2043 bool postComplete =
2044 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002045 if (postComplete)
2046 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002047 sendPowerControlEvent(Event::postCompleteAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002048 osIface->set_property("OperatingSystemState", std::string("Standby"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002049 }
2050 else
2051 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002052 sendPowerControlEvent(Event::postCompleteDeAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002053 osIface->set_property("OperatingSystemState", std::string("Inactive"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002054 }
2055 postCompleteEvent.async_wait(
2056 boost::asio::posix::stream_descriptor::wait_read,
2057 [](const boost::system::error_code ec) {
2058 if (ec)
2059 {
2060 std::cerr << "POST complete handler error: " << ec.message()
2061 << "\n";
2062 return;
2063 }
2064 postCompleteHandler();
2065 });
2066}
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302067
2068static int loadConfigValues()
2069{
2070 const std::string configFilePath =
2071 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2072 ".json";
2073 std::ifstream configFile(configFilePath.c_str());
2074 if (!configFile.is_open())
2075 {
2076 std::cerr << "loadConfigValues : Cannot open config path\n ";
2077 return -1;
2078 }
2079 auto data = nlohmann::json::parse(configFile, nullptr);
2080
2081 if (data.is_discarded())
2082 {
2083 std::cerr << "Power config readings JSON parser failure";
2084 return -1;
2085 }
2086
2087 if (data.contains("IdButton"))
2088 {
2089 idButtonName = data["IdButton"];
2090 }
2091
2092 if (data.contains("NMIButton"))
2093 {
2094 nmiButtonName = data["NMIButton"];
2095 }
2096
2097 if (data.contains("NMIOut"))
2098 {
2099 nmiOutName = data["NMIOut"];
2100 }
2101
2102 if (data.contains("PostComplete"))
2103 {
2104 postCompleteName = data["PostComplete"];
2105 }
2106
2107 if (data.contains("PwrButton"))
2108 {
2109 powerButtonName = data["PwrButton"];
2110 }
2111
2112 if (data.contains("PwrOK"))
2113 {
2114 powerOkName = data["PwrOK"];
2115 }
2116
2117 if (data.contains("PwrOut"))
2118 {
2119 powerOutName = data["PwrOut"];
2120 }
2121
2122 if (data.contains("RstButton"))
2123 {
2124 resetButtonName = data["RstButton"];
2125 }
2126
2127 if (data.contains("RstOut"))
2128 {
2129 resetOutName = data["RstOut"];
2130 }
2131
2132 if (data.contains("SIOOnCtl"))
2133 {
2134 sioOnControlName = data["SIOOnCtl"];
2135 }
2136
2137 if (data.contains("SIOPwrGd"))
2138 {
2139 sioPwrGoodName = data["SIOPwrGd"];
2140 }
2141
2142 if (data.contains("SIOS5"))
2143 {
2144 sioS5Name = data["SIOS5"];
2145 }
2146
2147 return 0;
2148}
2149
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002150} // namespace power_control
2151
2152int main(int argc, char* argv[])
2153{
2154 std::cerr << "Start Chassis power control service...\n";
2155 power_control::conn =
2156 std::make_shared<sdbusplus::asio::connection>(power_control::io);
2157
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302158 // Load GPIO's through json config file
2159 if (power_control::loadConfigValues() == -1)
2160 {
2161 std::cerr << "Host" << power_control::node << ": "
2162 << "Error in Parsing...\n";
2163 }
2164
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002165 // Request all the dbus names
2166 power_control::conn->request_name("xyz.openbmc_project.State.Host");
2167 power_control::conn->request_name("xyz.openbmc_project.State.Chassis");
2168 power_control::conn->request_name(
2169 "xyz.openbmc_project.State.OperatingSystem");
2170 power_control::conn->request_name("xyz.openbmc_project.Chassis.Buttons");
Chen Yugang174ec662019-08-19 19:58:49 +08002171 power_control::conn->request_name("xyz.openbmc_project.Control.Host.NMI");
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002172 power_control::conn->request_name(
2173 "xyz.openbmc_project.Control.Host.RestartCause");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002174
Priyatharshan P19c47a32020-08-12 18:16:43 +05302175 if (power_control::sioPwrGoodName.empty() ||
2176 power_control::sioOnControlName.empty() ||
2177 power_control::sioS5Name.empty())
2178 {
2179 power_control::sioEnabled = false;
2180 std::cerr << "SIO control GPIOs not defined, disable SIO support.\n";
2181 }
2182
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002183 // Request PS_PWROK GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302184 if (!power_control::powerOkName.empty())
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002185 {
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302186 if (!power_control::requestGPIOEvents(
2187 power_control::powerOkName, power_control::psPowerOKHandler,
2188 power_control::psPowerOKLine, power_control::psPowerOKEvent))
2189 {
2190 return -1;
2191 }
2192 }
2193 else
2194 {
2195 std::cerr
2196 << "PowerOk name should be configured from json config file\n";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002197 return -1;
2198 }
2199
Priyatharshan P19c47a32020-08-12 18:16:43 +05302200 if (power_control::sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002201 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05302202 // Request SIO_POWER_GOOD GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302203 if (!power_control::requestGPIOEvents(
2204 power_control::sioPwrGoodName,
2205 power_control::sioPowerGoodHandler,
2206 power_control::sioPowerGoodLine,
2207 power_control::sioPowerGoodEvent))
2208 {
2209 return -1;
2210 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002211
Priyatharshan P19c47a32020-08-12 18:16:43 +05302212 // Request SIO_ONCONTROL GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302213 if (!power_control::requestGPIOEvents(
2214 power_control::sioOnControlName,
2215 power_control::sioOnControlHandler,
2216 power_control::sioOnControlLine,
2217 power_control::sioOnControlEvent))
2218 {
2219 return -1;
2220 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002221
Priyatharshan P19c47a32020-08-12 18:16:43 +05302222 // Request SIO_S5 GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302223 if (!power_control::requestGPIOEvents(
2224 power_control::sioS5Name, power_control::sioS5Handler,
2225 power_control::sioS5Line, power_control::sioS5Event))
2226 {
2227 return -1;
2228 }
2229 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002230
2231 // Request POWER_BUTTON GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302232 if (!power_control::powerButtonName.empty())
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002233 {
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302234 if (!power_control::requestGPIOEvents(power_control::powerButtonName,
2235 power_control::powerButtonHandler,
2236 power_control::powerButtonLine,
2237 power_control::powerButtonEvent))
2238 {
2239 return -1;
2240 }
2241 }
2242 else
2243 {
2244 std::cerr
2245 << "powerButton name should be configured from json config file\n";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002246 return -1;
2247 }
2248
2249 // Request RESET_BUTTON GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302250 if (!power_control::resetButtonName.empty())
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002251 {
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302252 if (!power_control::requestGPIOEvents(power_control::resetButtonName,
2253 power_control::resetButtonHandler,
2254 power_control::resetButtonLine,
2255 power_control::resetButtonEvent))
2256 {
2257 return -1;
2258 }
2259 }
2260 else
2261 {
John Wang6c090072020-09-30 13:32:16 +08002262 std::cerr << "ResetButton not defined...\n";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002263 }
2264
2265 // Request NMI_BUTTON GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302266 if (!power_control::nmiButtonName.empty())
2267 {
2268 power_control::requestGPIOEvents(
2269 power_control::nmiButtonName, power_control::nmiButtonHandler,
2270 power_control::nmiButtonLine, power_control::nmiButtonEvent);
2271 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002272
2273 // Request ID_BUTTON GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302274 if (!power_control::idButtonName.empty())
2275 {
2276 power_control::requestGPIOEvents(
2277 power_control::idButtonName, power_control::idButtonHandler,
2278 power_control::idButtonLine, power_control::idButtonEvent);
2279 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002280
2281 // Request POST_COMPLETE GPIO events
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302282 if (!power_control::postCompleteName.empty())
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002283 {
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302284 if (!power_control::requestGPIOEvents(
2285 power_control::postCompleteName,
2286 power_control::postCompleteHandler,
2287 power_control::postCompleteLine,
2288 power_control::postCompleteEvent))
2289 {
2290 return -1;
2291 }
2292 }
2293 else
2294 {
2295 std::cerr
2296 << "postComplete name should be configured from json config file\n";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002297 return -1;
2298 }
2299
2300 // initialize NMI_OUT GPIO.
Vijay Khemka33a532d2019-11-14 16:50:35 -08002301 power_control::setGPIOOutput(power_control::nmiOutName, 0,
2302 power_control::nmiOutLine);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002303
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002304 // Initialize POWER_OUT and RESET_OUT GPIO.
2305 gpiod::line line;
2306 if (!power_control::setGPIOOutput(power_control::powerOutName, 1, line))
2307 {
2308 return -1;
2309 }
2310
2311 if (!power_control::setGPIOOutput(power_control::resetOutName, 1, line))
2312 {
2313 return -1;
2314 }
2315
2316 // Release line
2317 line.reset();
2318
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002319 // Initialize the power state
2320 power_control::powerState = power_control::PowerState::off;
2321 // Check power good
2322 if (power_control::psPowerOKLine.get_value() > 0)
2323 {
2324 power_control::powerState = power_control::PowerState::on;
2325 }
2326
2327 // Initialize the power state storage
2328 if (power_control::initializePowerStateStorage() < 0)
2329 {
2330 return -1;
2331 }
2332
2333 // Check if we need to start the Power Restore policy
2334 power_control::powerRestorePolicyCheck();
2335
Vijay Khemka33a532d2019-11-14 16:50:35 -08002336 if (power_control::nmiOutLine)
2337 power_control::nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002338
2339 std::cerr << "Initializing power state. ";
2340 power_control::logStateTransition(power_control::powerState);
2341
2342 // Power Control Service
2343 sdbusplus::asio::object_server hostServer =
2344 sdbusplus::asio::object_server(power_control::conn);
2345
2346 // Power Control Interface
2347 power_control::hostIface = hostServer.add_interface(
2348 "/xyz/openbmc_project/state/host0", "xyz.openbmc_project.State.Host");
2349
2350 power_control::hostIface->register_property(
2351 "RequestedHostTransition",
2352 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2353 [](const std::string& requested, std::string& resp) {
2354 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2355 {
2356 sendPowerControlEvent(
2357 power_control::Event::gracefulPowerOffRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002358 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002359 }
2360 else if (requested ==
2361 "xyz.openbmc_project.State.Host.Transition.On")
2362 {
2363 sendPowerControlEvent(power_control::Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002364 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002365 }
2366 else if (requested ==
2367 "xyz.openbmc_project.State.Host.Transition.Reboot")
2368 {
Jason M. Billse7520ba2020-01-31 11:19:03 -08002369 sendPowerControlEvent(power_control::Event::powerCycleRequest);
2370 addRestartCause(power_control::RestartCause::command);
2371 }
2372 else if (requested == "xyz.openbmc_project.State.Host.Transition."
2373 "GracefulWarmReboot")
2374 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002375 sendPowerControlEvent(
2376 power_control::Event::gracefulPowerCycleRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002377 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002378 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002379 else if (requested == "xyz.openbmc_project.State.Host.Transition."
2380 "ForceWarmReboot")
2381 {
2382 sendPowerControlEvent(power_control::Event::resetRequest);
2383 addRestartCause(power_control::RestartCause::command);
2384 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002385 else
2386 {
2387 std::cerr << "Unrecognized host state transition request.\n";
2388 throw std::invalid_argument("Unrecognized Transition Request");
2389 return 0;
2390 }
2391 resp = requested;
2392 return 1;
2393 });
2394 power_control::hostIface->register_property(
2395 "CurrentHostState",
2396 std::string(power_control::getHostState(power_control::powerState)));
2397
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002398 power_control::hostIface->initialize();
2399
2400 // Chassis Control Service
2401 sdbusplus::asio::object_server chassisServer =
2402 sdbusplus::asio::object_server(power_control::conn);
2403
2404 // Chassis Control Interface
2405 power_control::chassisIface =
2406 chassisServer.add_interface("/xyz/openbmc_project/state/chassis0",
2407 "xyz.openbmc_project.State.Chassis");
2408
2409 power_control::chassisIface->register_property(
2410 "RequestedPowerTransition",
2411 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
2412 [](const std::string& requested, std::string& resp) {
2413 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
2414 {
2415 sendPowerControlEvent(power_control::Event::powerOffRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002416 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002417 }
2418 else if (requested ==
2419 "xyz.openbmc_project.State.Chassis.Transition.On")
2420 {
2421 sendPowerControlEvent(power_control::Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002422 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002423 }
2424 else if (requested ==
2425 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2426 {
2427 sendPowerControlEvent(power_control::Event::powerCycleRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002428 addRestartCause(power_control::RestartCause::command);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002429 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002430 else
2431 {
2432 std::cerr << "Unrecognized chassis state transition request.\n";
2433 throw std::invalid_argument("Unrecognized Transition Request");
2434 return 0;
2435 }
2436 resp = requested;
2437 return 1;
2438 });
2439 power_control::chassisIface->register_property(
2440 "CurrentPowerState",
2441 std::string(power_control::getChassisState(power_control::powerState)));
2442 power_control::chassisIface->register_property(
2443 "LastStateChangeTime", power_control::getCurrentTimeMs());
2444
2445 power_control::chassisIface->initialize();
2446
Vijay Khemka04175c22020-10-09 14:28:11 -07002447#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002448 // Chassis System Service
2449 sdbusplus::asio::object_server chassisSysServer =
2450 sdbusplus::asio::object_server(power_control::conn);
2451
2452 // Chassis System Interface
2453 power_control::chassisSysIface = chassisSysServer.add_interface(
2454 "/xyz/openbmc_project/state/chassis_system0",
2455 "xyz.openbmc_project.State.Chassis");
2456
2457 power_control::chassisSysIface->register_property(
2458 "RequestedPowerTransition",
2459 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
2460 [](const std::string& requested, std::string& resp) {
2461 if (requested ==
2462 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2463 {
2464 power_control::systemReset();
2465 addRestartCause(power_control::RestartCause::command);
2466 }
2467 else
2468 {
2469 std::cerr << "Unrecognized chassis system state transition "
2470 "request.\n";
2471 throw std::invalid_argument("Unrecognized Transition Request");
2472 return 0;
2473 }
2474 resp = requested;
2475 return 1;
2476 });
2477 power_control::chassisSysIface->register_property(
2478 "CurrentPowerState",
2479 std::string(power_control::getChassisState(power_control::powerState)));
2480 power_control::chassisSysIface->register_property(
2481 "LastStateChangeTime", power_control::getCurrentTimeMs());
2482
2483 power_control::chassisSysIface->initialize();
Vijay Khemka04175c22020-10-09 14:28:11 -07002484#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002485
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002486 // Buttons Service
2487 sdbusplus::asio::object_server buttonsServer =
2488 sdbusplus::asio::object_server(power_control::conn);
2489
2490 // Power Button Interface
2491 power_control::powerButtonIface = buttonsServer.add_interface(
2492 "/xyz/openbmc_project/chassis/buttons/power",
2493 "xyz.openbmc_project.Chassis.Buttons");
2494
2495 power_control::powerButtonIface->register_property(
2496 "ButtonMasked", false, [](const bool requested, bool& current) {
2497 if (requested)
2498 {
2499 if (power_control::powerButtonMask)
2500 {
2501 return 1;
2502 }
2503 if (!power_control::setGPIOOutput(
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002504 power_control::powerOutName, 1,
2505 power_control::powerButtonMask))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002506 {
2507 throw std::runtime_error("Failed to request GPIO");
2508 return 0;
2509 }
2510 std::cerr << "Power Button Masked.\n";
2511 }
2512 else
2513 {
2514 if (!power_control::powerButtonMask)
2515 {
2516 return 1;
2517 }
2518 std::cerr << "Power Button Un-masked\n";
2519 power_control::powerButtonMask.reset();
2520 }
2521 // Update the mask setting
2522 current = requested;
2523 return 1;
2524 });
2525
2526 // Check power button state
2527 bool powerButtonPressed = power_control::powerButtonLine.get_value() == 0;
2528 power_control::powerButtonIface->register_property("ButtonPressed",
2529 powerButtonPressed);
2530
2531 power_control::powerButtonIface->initialize();
2532
2533 // Reset Button Interface
John Wang6c090072020-09-30 13:32:16 +08002534 if (!power_control::resetButtonName.empty())
2535 {
2536 power_control::resetButtonIface = buttonsServer.add_interface(
2537 "/xyz/openbmc_project/chassis/buttons/reset",
2538 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002539
John Wang6c090072020-09-30 13:32:16 +08002540 power_control::resetButtonIface->register_property(
2541 "ButtonMasked", false, [](const bool requested, bool& current) {
2542 if (requested)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002543 {
John Wang6c090072020-09-30 13:32:16 +08002544 if (power_control::resetButtonMask)
2545 {
2546 return 1;
2547 }
2548 if (!power_control::setGPIOOutput(
2549 power_control::resetOutName, 1,
2550 power_control::resetButtonMask))
2551 {
2552 throw std::runtime_error("Failed to request GPIO");
2553 return 0;
2554 }
2555 std::cerr << "Reset Button Masked.\n";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002556 }
John Wang6c090072020-09-30 13:32:16 +08002557 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002558 {
John Wang6c090072020-09-30 13:32:16 +08002559 if (!power_control::resetButtonMask)
2560 {
2561 return 1;
2562 }
2563 std::cerr << "Reset Button Un-masked\n";
2564 power_control::resetButtonMask.reset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002565 }
John Wang6c090072020-09-30 13:32:16 +08002566 // Update the mask setting
2567 current = requested;
2568 return 1;
2569 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002570
John Wang6c090072020-09-30 13:32:16 +08002571 // Check reset button state
2572 bool resetButtonPressed =
2573 power_control::resetButtonLine.get_value() == 0;
2574 power_control::resetButtonIface->register_property("ButtonPressed",
2575 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002576
John Wang6c090072020-09-30 13:32:16 +08002577 power_control::resetButtonIface->initialize();
2578 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002579
Vijay Khemka33a532d2019-11-14 16:50:35 -08002580 if (power_control::nmiButtonLine)
2581 {
2582 // NMI Button Interface
2583 power_control::nmiButtonIface = buttonsServer.add_interface(
2584 "/xyz/openbmc_project/chassis/buttons/nmi",
2585 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002586
Vijay Khemka33a532d2019-11-14 16:50:35 -08002587 power_control::nmiButtonIface->register_property(
2588 "ButtonMasked", false, [](const bool requested, bool& current) {
2589 if (power_control::nmiButtonMasked == requested)
2590 {
2591 // NMI button mask is already set as requested, so no change
2592 return 1;
2593 }
2594 if (requested)
2595 {
2596 std::cerr << "NMI Button Masked.\n";
2597 power_control::nmiButtonMasked = true;
2598 }
2599 else
2600 {
2601 std::cerr << "NMI Button Un-masked.\n";
2602 power_control::nmiButtonMasked = false;
2603 }
2604 // Update the mask setting
2605 current = power_control::nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002606 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08002607 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002608
Vijay Khemka33a532d2019-11-14 16:50:35 -08002609 // Check NMI button state
2610 bool nmiButtonPressed = power_control::nmiButtonLine.get_value() == 0;
2611 power_control::nmiButtonIface->register_property("ButtonPressed",
2612 nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002613
Vijay Khemka33a532d2019-11-14 16:50:35 -08002614 power_control::nmiButtonIface->initialize();
2615 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002616
Vijay Khemka33a532d2019-11-14 16:50:35 -08002617 if (power_control::nmiOutLine)
2618 {
2619 // NMI out Service
2620 sdbusplus::asio::object_server nmiOutServer =
2621 sdbusplus::asio::object_server(power_control::conn);
Chen Yugang174ec662019-08-19 19:58:49 +08002622
Vijay Khemka33a532d2019-11-14 16:50:35 -08002623 // NMI out Interface
2624 power_control::nmiOutIface =
2625 nmiOutServer.add_interface("/xyz/openbmc_project/control/host0/nmi",
2626 "xyz.openbmc_project.Control.Host.NMI");
2627 power_control::nmiOutIface->register_method("NMI",
2628 power_control::nmiReset);
2629 power_control::nmiOutIface->initialize();
2630 }
Chen Yugang174ec662019-08-19 19:58:49 +08002631
Vijay Khemka33a532d2019-11-14 16:50:35 -08002632 if (power_control::idButtonLine)
2633 {
2634 // ID Button Interface
2635 power_control::idButtonIface = buttonsServer.add_interface(
2636 "/xyz/openbmc_project/chassis/buttons/id",
2637 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002638
Vijay Khemka33a532d2019-11-14 16:50:35 -08002639 // Check ID button state
2640 bool idButtonPressed = power_control::idButtonLine.get_value() == 0;
2641 power_control::idButtonIface->register_property("ButtonPressed",
2642 idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002643
Vijay Khemka33a532d2019-11-14 16:50:35 -08002644 power_control::idButtonIface->initialize();
2645 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002646
2647 // OS State Service
2648 sdbusplus::asio::object_server osServer =
2649 sdbusplus::asio::object_server(power_control::conn);
2650
2651 // OS State Interface
2652 power_control::osIface = osServer.add_interface(
2653 "/xyz/openbmc_project/state/os",
2654 "xyz.openbmc_project.State.OperatingSystem.Status");
2655
2656 // Get the initial OS state based on POST complete
2657 // 0: Asserted, OS state is "Standby" (ready to boot)
2658 // 1: De-Asserted, OS state is "Inactive"
2659 std::string osState = power_control::postCompleteLine.get_value() > 0
2660 ? "Inactive"
2661 : "Standby";
2662
2663 power_control::osIface->register_property("OperatingSystemState",
2664 std::string(osState));
2665
2666 power_control::osIface->initialize();
2667
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002668 // Restart Cause Service
2669 sdbusplus::asio::object_server restartCauseServer =
2670 sdbusplus::asio::object_server(power_control::conn);
2671
2672 // Restart Cause Interface
2673 power_control::restartCauseIface = restartCauseServer.add_interface(
2674 "/xyz/openbmc_project/control/host0/restart_cause",
2675 "xyz.openbmc_project.Control.Host.RestartCause");
2676
2677 power_control::restartCauseIface->register_property(
2678 "RestartCause",
2679 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
2680
2681 power_control::restartCauseIface->register_property(
2682 "RequestedRestartCause",
2683 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
2684 [](const std::string& requested, std::string& resp) {
2685 if (requested ==
2686 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
2687 {
2688 power_control::addRestartCause(
2689 power_control::RestartCause::watchdog);
2690 }
2691 else
2692 {
2693 throw std::invalid_argument(
2694 "Unrecognized RestartCause Request");
2695 return 0;
2696 }
2697
2698 std::cerr << "RestartCause requested: " << requested << "\n";
2699 resp = requested;
2700 return 1;
2701 });
2702
2703 power_control::restartCauseIface->initialize();
2704
Yong Li8d660212019-12-27 10:18:10 +08002705 power_control::currentHostStateMonitor();
2706
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002707 power_control::io.run();
2708
2709 return 0;
2710}