blob: 58e7a8b9c0e90a9bc32d0475fd5aa40c4f8f1a00 [file] [log] [blame]
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001/*
2// Copyright (c) 2018-2019 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#include "i2c.hpp"
17
18#include <sys/sysinfo.h>
19#include <systemd/sd-journal.h>
20
Jason M. Billse63dea02020-08-27 12:07:35 -070021#include <boost/asio/io_service.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070022#include <boost/asio/posix/stream_descriptor.hpp>
Jason M. Billse63dea02020-08-27 12:07:35 -070023#include <boost/asio/steady_timer.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070024#include <boost/container/flat_map.hpp>
Jason M. Bills7d4aaac2019-09-19 14:03:44 -070025#include <boost/container/flat_set.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070026#include <gpiod.hpp>
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053027#include <nlohmann/json.hpp>
Vijay Khemkafc1ecc52020-04-01 10:49:28 -070028#include <phosphor-logging/log.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070029#include <sdbusplus/asio/object_server.hpp>
Vijay Khemka2b6f4422020-05-29 11:13:23 -070030
31#include <filesystem>
32#include <fstream>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070033#include <string_view>
34
35namespace power_control
36{
37static boost::asio::io_service io;
38std::shared_ptr<sdbusplus::asio::connection> conn;
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053039
40static std::string node = "0";
41
Priyatharshan P70120512020-09-16 18:47:20 +053042enum class DbusConfigType
43{
44 name = 1,
45 path,
46 interface,
47 property
48};
49boost::container::flat_map<DbusConfigType, std::string> dbusParams = {
50 {DbusConfigType::name, "DbusName"},
51 {DbusConfigType::path, "Path"},
52 {DbusConfigType::interface, "Interface"},
53 {DbusConfigType::property, "Property"}};
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053054
Priyatharshan P70120512020-09-16 18:47:20 +053055enum class ConfigType
56{
57 GPIO = 1,
58 DBUS
59};
60
61struct ConfigData
62{
63 std::string name;
64 std::string lineName;
65 std::string dbusName;
66 std::string path;
67 std::string interface;
68 ConfigType type;
69};
70
71static ConfigData powerOutConfig;
72static ConfigData powerOkConfig;
73static ConfigData resetOutConfig;
74static ConfigData nmiOutConfig;
75static ConfigData sioPwrGoodConfig;
76static ConfigData sioOnControlConfig;
77static ConfigData sioS5Config;
78static ConfigData postCompleteConfig;
79static ConfigData powerButtonConfig;
80static ConfigData resetButtonConfig;
81static ConfigData idButtonConfig;
82static ConfigData nmiButtonConfig;
Naveen Moses117c34e2021-05-26 20:10:51 +053083static ConfigData slotPowerConfig;
84
Priyatharshan P70120512020-09-16 18:47:20 +053085// map for storing list of gpio parameters whose config are to be read from x86
86// power control json config
87boost::container::flat_map<std::string, ConfigData*> powerSignalMap = {
88 {"PowerOut", &powerOutConfig},
89 {"PowerOk", &powerOkConfig},
90 {"ResetOut", &resetOutConfig},
91 {"NMIOut", &nmiOutConfig},
92 {"SioPowerGood", &sioPwrGoodConfig},
93 {"SioOnControl", &sioOnControlConfig},
94 {"SIOS5", &sioS5Config},
95 {"PostComplete", &postCompleteConfig},
96 {"PowerButton", &powerButtonConfig},
97 {"ResetButton", &resetButtonConfig},
98 {"IdButton", &idButtonConfig},
Naveen Moses117c34e2021-05-26 20:10:51 +053099 {"NMIButton", &nmiButtonConfig},
100 {"SlotPower", &slotPowerConfig}};
Priyatharshan P70120512020-09-16 18:47:20 +0530101
102static std::string hostDbusName = "xyz.openbmc_project.State.Host";
103static std::string chassisDbusName = "xyz.openbmc_project.State.Chassis";
104static std::string osDbusName = "xyz.openbmc_project.State.OperatingSystem";
105static std::string buttonDbusName = "xyz.openbmc_project.Chassis.Buttons";
106static std::string nmiDbusName = "xyz.openbmc_project.Control.Host.NMI";
107static std::string rstCauseDbusName =
108 "xyz.openbmc_project.Control.Host.RestartCause";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700109static std::shared_ptr<sdbusplus::asio::dbus_interface> hostIface;
110static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700111#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -0700112static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSysIface;
Naveen Moses117c34e2021-05-26 20:10:51 +0530113static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSlotIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700114#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700115static std::shared_ptr<sdbusplus::asio::dbus_interface> powerButtonIface;
116static std::shared_ptr<sdbusplus::asio::dbus_interface> resetButtonIface;
117static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiButtonIface;
118static std::shared_ptr<sdbusplus::asio::dbus_interface> osIface;
119static std::shared_ptr<sdbusplus::asio::dbus_interface> idButtonIface;
Chen Yugang174ec662019-08-19 19:58:49 +0800120static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiOutIface;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700121static std::shared_ptr<sdbusplus::asio::dbus_interface> restartCauseIface;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700122
123static gpiod::line powerButtonMask;
124static gpiod::line resetButtonMask;
125static bool nmiButtonMasked = false;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700126
Priyatharshan P70120512020-09-16 18:47:20 +0530127// This map contains all timer values that are to be read from json config
128boost::container::flat_map<std::string, int> TimerMap = {
129 {"powerPulseTimeMs", 200},
130 {"forceOffPulseTimeMs", 15000},
131 {"resetPulseTimeMs", 500},
132 {"powerCycleTimeMs", 5000},
133 {"sioPowerGoodWatchdogTimeMs", 1000},
134 {"psPowerOKWatchdogTimeMs", 8000},
135 {"gracefulPowerOffTimeS", (5 * 60)},
136 {"warmResetCheckTimeMs", 500},
Naveen Moses117c34e2021-05-26 20:10:51 +0530137 {"powerOffSaveTimeMs", 7000},
138 {"slotPowerCycleTimeMs", 200}};
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700139const static std::filesystem::path powerControlDir = "/var/lib/power-control";
140const static constexpr std::string_view powerStateFile = "power-state";
141
142static bool nmiEnabled = true;
Priyatharshan P19c47a32020-08-12 18:16:43 +0530143static bool sioEnabled = true;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700144
145// Timers
146// Time holding GPIOs asserted
147static boost::asio::steady_timer gpioAssertTimer(io);
148// Time between off and on during a power cycle
149static boost::asio::steady_timer powerCycleTimer(io);
150// Time OS gracefully powering off
151static boost::asio::steady_timer gracefulPowerOffTimer(io);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700152// Time the warm reset check
153static boost::asio::steady_timer warmResetCheckTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700154// Time power supply power OK assertion on power-on
155static boost::asio::steady_timer psPowerOKWatchdogTimer(io);
156// Time SIO power good assertion on power-on
157static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io);
158// Time power-off state save for power loss tracking
159static boost::asio::steady_timer powerStateSaveTimer(io);
160// POH timer
161static boost::asio::steady_timer pohCounterTimer(io);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700162// Time when to allow restart cause updates
163static boost::asio::steady_timer restartCauseTimer(io);
Naveen Moses117c34e2021-05-26 20:10:51 +0530164static boost::asio::steady_timer slotPowerCycleTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700165
166// GPIO Lines and Event Descriptors
167static gpiod::line psPowerOKLine;
168static boost::asio::posix::stream_descriptor psPowerOKEvent(io);
169static gpiod::line sioPowerGoodLine;
170static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io);
171static gpiod::line sioOnControlLine;
172static boost::asio::posix::stream_descriptor sioOnControlEvent(io);
173static gpiod::line sioS5Line;
174static boost::asio::posix::stream_descriptor sioS5Event(io);
175static gpiod::line powerButtonLine;
176static boost::asio::posix::stream_descriptor powerButtonEvent(io);
177static gpiod::line resetButtonLine;
178static boost::asio::posix::stream_descriptor resetButtonEvent(io);
179static gpiod::line nmiButtonLine;
180static boost::asio::posix::stream_descriptor nmiButtonEvent(io);
181static gpiod::line idButtonLine;
182static boost::asio::posix::stream_descriptor idButtonEvent(io);
183static gpiod::line postCompleteLine;
184static boost::asio::posix::stream_descriptor postCompleteEvent(io);
185static gpiod::line nmiOutLine;
Naveen Moses117c34e2021-05-26 20:10:51 +0530186static gpiod::line slotPowerLine;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700187
188static constexpr uint8_t beepPowerFail = 8;
189
190static void beep(const uint8_t& beepPriority)
191{
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800192 std::string logMsg = "Beep with priority: " + std::to_string(beepPriority);
193 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700194
195 conn->async_method_call(
196 [](boost::system::error_code ec) {
197 if (ec)
198 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800199 std::string errMsg =
200 "beep returned error with async_method_call (ec = " +
201 ec.message();
202 phosphor::logging::log<phosphor::logging::level::ERR>(
203 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700204 return;
205 }
206 },
207 "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
208 "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
209}
210
211enum class PowerState
212{
213 on,
214 waitForPSPowerOK,
215 waitForSIOPowerGood,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700216 off,
217 transitionToOff,
218 gracefulTransitionToOff,
219 cycleOff,
220 transitionToCycleOff,
221 gracefulTransitionToCycleOff,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700222 checkForWarmReset,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700223};
224static PowerState powerState;
225static std::string getPowerStateName(PowerState state)
226{
227 switch (state)
228 {
229 case PowerState::on:
230 return "On";
231 break;
232 case PowerState::waitForPSPowerOK:
233 return "Wait for Power Supply Power OK";
234 break;
235 case PowerState::waitForSIOPowerGood:
236 return "Wait for SIO Power Good";
237 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700238 case PowerState::off:
239 return "Off";
240 break;
241 case PowerState::transitionToOff:
242 return "Transition to Off";
243 break;
244 case PowerState::gracefulTransitionToOff:
245 return "Graceful Transition to Off";
246 break;
247 case PowerState::cycleOff:
248 return "Power Cycle Off";
249 break;
250 case PowerState::transitionToCycleOff:
251 return "Transition to Power Cycle Off";
252 break;
253 case PowerState::gracefulTransitionToCycleOff:
254 return "Graceful Transition to Power Cycle Off";
255 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700256 case PowerState::checkForWarmReset:
257 return "Check for Warm Reset";
258 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700259 default:
260 return "unknown state: " + std::to_string(static_cast<int>(state));
261 break;
262 }
263}
264static void logStateTransition(const PowerState state)
265{
Vijay Khemkad6c5ad12020-05-27 14:57:52 -0700266 std::string logMsg =
267 "Host0: Moving to \"" + getPowerStateName(state) + "\" state";
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700268 phosphor::logging::log<phosphor::logging::level::INFO>(
269 logMsg.c_str(),
Vijay Khemkad6c5ad12020-05-27 14:57:52 -0700270 phosphor::logging::entry("STATE=%s", getPowerStateName(state).c_str()),
271 phosphor::logging::entry("HOST=0"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700272}
273
274enum class Event
275{
276 psPowerOKAssert,
277 psPowerOKDeAssert,
278 sioPowerGoodAssert,
279 sioPowerGoodDeAssert,
280 sioS5Assert,
281 sioS5DeAssert,
Jason M. Billsfb957332021-01-28 13:18:46 -0800282 pltRstAssert,
283 pltRstDeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700284 postCompleteAssert,
285 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700286 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700287 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700288 powerCycleTimerExpired,
289 psPowerOKWatchdogTimerExpired,
290 sioPowerGoodWatchdogTimerExpired,
291 gracefulPowerOffTimerExpired,
292 powerOnRequest,
293 powerOffRequest,
294 powerCycleRequest,
295 resetRequest,
296 gracefulPowerOffRequest,
297 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700298 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700299};
300static std::string getEventName(Event event)
301{
302 switch (event)
303 {
304 case Event::psPowerOKAssert:
305 return "power supply power OK assert";
306 break;
307 case Event::psPowerOKDeAssert:
308 return "power supply power OK de-assert";
309 break;
310 case Event::sioPowerGoodAssert:
311 return "SIO power good assert";
312 break;
313 case Event::sioPowerGoodDeAssert:
314 return "SIO power good de-assert";
315 break;
316 case Event::sioS5Assert:
317 return "SIO S5 assert";
318 break;
319 case Event::sioS5DeAssert:
320 return "SIO S5 de-assert";
321 break;
Jason M. Billsfb957332021-01-28 13:18:46 -0800322 case Event::pltRstAssert:
323 return "PLT_RST assert";
324 break;
325 case Event::pltRstDeAssert:
326 return "PLT_RST de-assert";
327 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700328 case Event::postCompleteAssert:
329 return "POST Complete assert";
330 break;
331 case Event::postCompleteDeAssert:
332 return "POST Complete de-assert";
333 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700334 case Event::powerButtonPressed:
335 return "power button pressed";
336 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700337 case Event::resetButtonPressed:
338 return "reset button pressed";
339 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700340 case Event::powerCycleTimerExpired:
341 return "power cycle timer expired";
342 break;
343 case Event::psPowerOKWatchdogTimerExpired:
344 return "power supply power OK watchdog timer expired";
345 break;
346 case Event::sioPowerGoodWatchdogTimerExpired:
347 return "SIO power good watchdog timer expired";
348 break;
349 case Event::gracefulPowerOffTimerExpired:
350 return "graceful power-off timer expired";
351 break;
352 case Event::powerOnRequest:
353 return "power-on request";
354 break;
355 case Event::powerOffRequest:
356 return "power-off request";
357 break;
358 case Event::powerCycleRequest:
359 return "power-cycle request";
360 break;
361 case Event::resetRequest:
362 return "reset request";
363 break;
364 case Event::gracefulPowerOffRequest:
365 return "graceful power-off request";
366 break;
367 case Event::gracefulPowerCycleRequest:
368 return "graceful power-cycle request";
369 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700370 case Event::warmResetDetected:
371 return "warm reset detected";
372 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700373 default:
374 return "unknown event: " + std::to_string(static_cast<int>(event));
375 break;
376 }
377}
378static void logEvent(const std::string_view stateHandler, const Event event)
379{
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700380 std::string logMsg{stateHandler};
381 logMsg += ": " + getEventName(event) + " event received";
382 phosphor::logging::log<phosphor::logging::level::INFO>(
383 logMsg.c_str(),
384 phosphor::logging::entry("EVENT=%s", getEventName(event).c_str()));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700385}
386
387// Power state handlers
388static void powerStateOn(const Event event);
389static void powerStateWaitForPSPowerOK(const Event event);
390static void powerStateWaitForSIOPowerGood(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700391static void powerStateOff(const Event event);
392static void powerStateTransitionToOff(const Event event);
393static void powerStateGracefulTransitionToOff(const Event event);
394static void powerStateCycleOff(const Event event);
395static void powerStateTransitionToCycleOff(const Event event);
396static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700397static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700398
399static std::function<void(const Event)> getPowerStateHandler(PowerState state)
400{
401 switch (state)
402 {
403 case PowerState::on:
404 return powerStateOn;
405 break;
406 case PowerState::waitForPSPowerOK:
407 return powerStateWaitForPSPowerOK;
408 break;
409 case PowerState::waitForSIOPowerGood:
410 return powerStateWaitForSIOPowerGood;
411 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700412 case PowerState::off:
413 return powerStateOff;
414 break;
415 case PowerState::transitionToOff:
416 return powerStateTransitionToOff;
417 break;
418 case PowerState::gracefulTransitionToOff:
419 return powerStateGracefulTransitionToOff;
420 break;
421 case PowerState::cycleOff:
422 return powerStateCycleOff;
423 break;
424 case PowerState::transitionToCycleOff:
425 return powerStateTransitionToCycleOff;
426 break;
427 case PowerState::gracefulTransitionToCycleOff:
428 return powerStateGracefulTransitionToCycleOff;
429 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700430 case PowerState::checkForWarmReset:
431 return powerStateCheckForWarmReset;
432 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700433 default:
Zev Weiss047bcb52020-08-20 21:28:11 +0000434 return nullptr;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700435 break;
436 }
437};
438
439static void sendPowerControlEvent(const Event event)
440{
441 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
442 if (handler == nullptr)
443 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800444 std::string errMsg = "Failed to find handler for power state: " +
445 std::to_string(static_cast<int>(powerState));
446 phosphor::logging::log<phosphor::logging::level::INFO>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700447 return;
448 }
449 handler(event);
450}
451
452static uint64_t getCurrentTimeMs()
453{
454 struct timespec time = {};
455
456 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
457 {
458 return 0;
459 }
460 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
461 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
462
463 return currentTimeMs;
464}
465
466static constexpr std::string_view getHostState(const PowerState state)
467{
468 switch (state)
469 {
470 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700471 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700472 case PowerState::gracefulTransitionToCycleOff:
473 return "xyz.openbmc_project.State.Host.HostState.Running";
474 break;
475 case PowerState::waitForPSPowerOK:
476 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700477 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700478 case PowerState::transitionToOff:
479 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700480 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700481 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700482 return "xyz.openbmc_project.State.Host.HostState.Off";
483 break;
484 default:
485 return "";
486 break;
487 }
488};
489static constexpr std::string_view getChassisState(const PowerState state)
490{
491 switch (state)
492 {
493 case PowerState::on:
494 case PowerState::transitionToOff:
495 case PowerState::gracefulTransitionToOff:
496 case PowerState::transitionToCycleOff:
497 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700498 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700499 return "xyz.openbmc_project.State.Chassis.PowerState.On";
500 break;
501 case PowerState::waitForPSPowerOK:
502 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700503 case PowerState::off:
504 case PowerState::cycleOff:
505 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
506 break;
507 default:
508 return "";
509 break;
510 }
511};
Naveen Moses117c34e2021-05-26 20:10:51 +0530512#ifdef CHASSIS_SYSTEM_RESET
513enum class SlotPowerState
514{
515 on,
516 off,
517};
518static SlotPowerState slotPowerState;
519static constexpr std::string_view getSlotState(const SlotPowerState state)
520{
521 switch (state)
522 {
523 case SlotPowerState::on:
524 return "xyz.openbmc_project.State.Chassis.PowerState.On";
525 break;
526 case SlotPowerState::off:
527 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
528 break;
529 default:
530 return "";
531 break;
532 }
533};
534static void setSlotPowerState(const SlotPowerState state)
535{
536 slotPowerState = state;
537 chassisSlotIface->set_property("CurrentPowerState",
538 std::string(getSlotState(slotPowerState)));
539 chassisSlotIface->set_property("LastStateChangeTime", getCurrentTimeMs());
540}
541#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700542static void savePowerState(const PowerState state)
543{
544 powerStateSaveTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +0530545 std::chrono::milliseconds(TimerMap["powerOffSaveTimeMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700546 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
547 if (ec)
548 {
549 // operation_aborted is expected if timer is canceled before
550 // completion.
551 if (ec != boost::asio::error::operation_aborted)
552 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800553 std::string errMsg =
554 "Power-state save async_wait failed: " + ec.message();
555 phosphor::logging::log<phosphor::logging::level::ERR>(
556 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700557 }
558 return;
559 }
560 std::ofstream powerStateStream(powerControlDir / powerStateFile);
561 powerStateStream << getChassisState(state);
562 });
563}
564static void setPowerState(const PowerState state)
565{
566 powerState = state;
567 logStateTransition(state);
568
569 hostIface->set_property("CurrentHostState",
570 std::string(getHostState(powerState)));
571
572 chassisIface->set_property("CurrentPowerState",
573 std::string(getChassisState(powerState)));
574 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
575
576 // Save the power state for the restore policy
577 savePowerState(state);
578}
579
580enum class RestartCause
581{
582 command,
583 resetButton,
584 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700585 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700586 powerPolicyOn,
587 powerPolicyRestore,
588 softReset,
589};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700590static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700591static std::string getRestartCause(RestartCause cause)
592{
593 switch (cause)
594 {
595 case RestartCause::command:
596 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
597 break;
598 case RestartCause::resetButton:
599 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
600 break;
601 case RestartCause::powerButton:
602 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
603 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700604 case RestartCause::watchdog:
605 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
606 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700607 case RestartCause::powerPolicyOn:
608 return "xyz.openbmc_project.State.Host.RestartCause."
609 "PowerPolicyAlwaysOn";
610 break;
611 case RestartCause::powerPolicyRestore:
612 return "xyz.openbmc_project.State.Host.RestartCause."
613 "PowerPolicyPreviousState";
614 break;
615 case RestartCause::softReset:
616 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
617 break;
618 default:
619 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
620 break;
621 }
622}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700623static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700624{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700625 // Add this to the set of causes for this restart
626 causeSet.insert(cause);
627}
628static void clearRestartCause()
629{
630 // Clear the set for the next restart
631 causeSet.clear();
632}
633static void setRestartCauseProperty(const std::string& cause)
634{
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800635 std::string logMsg = "RestartCause set to " + cause;
636 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700637 restartCauseIface->set_property("RestartCause", cause);
638}
Rashmi RV89f61312020-01-22 15:41:50 +0530639
640static void resetACBootProperty()
641{
642 if ((causeSet.contains(RestartCause::command)) ||
643 (causeSet.contains(RestartCause::softReset)))
644 {
645 conn->async_method_call(
646 [](boost::system::error_code ec) {
647 if (ec)
648 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800649 phosphor::logging::log<phosphor::logging::level::ERR>(
650 "failed to reset ACBoot property");
Rashmi RV89f61312020-01-22 15:41:50 +0530651 }
652 },
653 "xyz.openbmc_project.Settings",
654 "/xyz/openbmc_project/control/host0/ac_boot",
655 "org.freedesktop.DBus.Properties", "Set",
656 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
657 std::variant<std::string>{"False"});
658 }
659}
660
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700661static void setRestartCause()
662{
663 // Determine the actual restart cause based on the set of causes
664 std::string restartCause =
665 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
666 if (causeSet.contains(RestartCause::watchdog))
667 {
668 restartCause = getRestartCause(RestartCause::watchdog);
669 }
670 else if (causeSet.contains(RestartCause::command))
671 {
672 restartCause = getRestartCause(RestartCause::command);
673 }
674 else if (causeSet.contains(RestartCause::resetButton))
675 {
676 restartCause = getRestartCause(RestartCause::resetButton);
677 }
678 else if (causeSet.contains(RestartCause::powerButton))
679 {
680 restartCause = getRestartCause(RestartCause::powerButton);
681 }
682 else if (causeSet.contains(RestartCause::powerPolicyOn))
683 {
684 restartCause = getRestartCause(RestartCause::powerPolicyOn);
685 }
686 else if (causeSet.contains(RestartCause::powerPolicyRestore))
687 {
688 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
689 }
690 else if (causeSet.contains(RestartCause::softReset))
691 {
692 restartCause = getRestartCause(RestartCause::softReset);
693 }
694
695 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700696}
697
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700698static void systemPowerGoodFailedLog()
699{
700 sd_journal_send(
701 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
702 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
703 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Priyatharshan P70120512020-09-16 18:47:20 +0530704 TimerMap["sioPowerGoodWatchdogTimeMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700705}
706
707static void psPowerOKFailedLog()
708{
709 sd_journal_send(
710 "MESSAGE=PowerControl: power supply power good failed to assert",
711 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
712 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Priyatharshan P70120512020-09-16 18:47:20 +0530713 TimerMap["psPowerOKWatchdogTimeMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700714}
715
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700716static void powerRestorePolicyLog()
717{
718 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
719 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
720 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
721}
722
723static void powerButtonPressLog()
724{
725 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
726 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
727 "OpenBMC.0.1.PowerButtonPressed", NULL);
728}
729
730static void resetButtonPressLog()
731{
732 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
733 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
734 "OpenBMC.0.1.ResetButtonPressed", NULL);
735}
736
737static void nmiButtonPressLog()
738{
739 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
740 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
741 "OpenBMC.0.1.NMIButtonPressed", NULL);
742}
743
744static void nmiDiagIntLog()
745{
746 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
747 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
748 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
749}
750
751static int initializePowerStateStorage()
752{
753 // create the power control directory if it doesn't exist
754 std::error_code ec;
755 if (!(std::filesystem::create_directories(powerControlDir, ec)))
756 {
757 if (ec.value() != 0)
758 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800759 std::string errMsg =
760 "failed to create " + powerControlDir.string() + ec.message();
761 phosphor::logging::log<phosphor::logging::level::ERR>(
762 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700763 return -1;
764 }
765 }
766 // Create the power state file if it doesn't exist
767 if (!std::filesystem::exists(powerControlDir / powerStateFile))
768 {
769 std::ofstream powerStateStream(powerControlDir / powerStateFile);
770 powerStateStream << getChassisState(powerState);
771 }
772 return 0;
773}
774
775static bool wasPowerDropped()
776{
777 std::ifstream powerStateStream(powerControlDir / powerStateFile);
778 if (!powerStateStream.is_open())
779 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800780 phosphor::logging::log<phosphor::logging::level::ERR>(
781 "Failed to open power state file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700782 return false;
783 }
784
785 std::string state;
786 std::getline(powerStateStream, state);
787 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
788}
789
790static void invokePowerRestorePolicy(const std::string& policy)
791{
792 // Async events may call this twice, but we only want to run once
793 static bool policyInvoked = false;
794 if (policyInvoked)
795 {
796 return;
797 }
798 policyInvoked = true;
799
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800800 std::string logMsg = "Power restore delay expired, invoking " + policy;
801 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700802 if (policy ==
803 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
804 {
805 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700806 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700807 }
808 else if (policy == "xyz.openbmc_project.Control.Power.RestorePolicy."
809 "Policy.Restore")
810 {
811 if (wasPowerDropped())
812 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800813 phosphor::logging::log<phosphor::logging::level::INFO>(
814 "Power was dropped, restoring Host On state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700815 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700816 setRestartCauseProperty(
817 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700818 }
819 else
820 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800821 phosphor::logging::log<phosphor::logging::level::INFO>(
822 "No power drop, restoring Host Off state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700823 }
824 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -0700825 // We're done with the previous power state for the restore policy, so store
826 // the current state
827 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700828}
829
830static void powerRestorePolicyDelay(int delay)
831{
832 // Async events may call this twice, but we only want to run once
833 static bool delayStarted = false;
834 if (delayStarted)
835 {
836 return;
837 }
838 delayStarted = true;
839 // Calculate the delay from now to meet the requested delay
840 // Subtract the approximate uboot time
841 static constexpr const int ubootSeconds = 20;
842 delay -= ubootSeconds;
843 // Subtract the time since boot
844 struct sysinfo info = {};
845 if (sysinfo(&info) == 0)
846 {
847 delay -= info.uptime;
848 }
849 // 0 is the minimum delay
850 delay = std::max(delay, 0);
851
852 static boost::asio::steady_timer powerRestorePolicyTimer(io);
853 powerRestorePolicyTimer.expires_after(std::chrono::seconds(delay));
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800854 std::string logMsg =
855 "Power restore delay of " + std::to_string(delay) + " seconds started";
856 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700857 powerRestorePolicyTimer.async_wait([](const boost::system::error_code ec) {
858 if (ec)
859 {
860 // operation_aborted is expected if timer is canceled before
861 // completion.
862 if (ec != boost::asio::error::operation_aborted)
863 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800864 std::string errMsg =
865 "power restore policy async_wait failed: " + ec.message();
866 phosphor::logging::log<phosphor::logging::level::ERR>(
867 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700868 }
869 return;
870 }
871 // Get Power Restore Policy
872 // In case PowerRestorePolicy is not available, set a match for it
873 static std::unique_ptr<sdbusplus::bus::match::match>
874 powerRestorePolicyMatch = std::make_unique<
875 sdbusplus::bus::match::match>(
876 *conn,
877 "type='signal',interface='org.freedesktop.DBus.Properties',"
878 "member='PropertiesChanged',arg0namespace='xyz.openbmc_"
879 "project.Control.Power.RestorePolicy'",
880 [](sdbusplus::message::message& msg) {
881 std::string interfaceName;
882 boost::container::flat_map<std::string,
883 std::variant<std::string>>
884 propertiesChanged;
885 std::string policy;
886 try
887 {
888 msg.read(interfaceName, propertiesChanged);
889 policy = std::get<std::string>(
890 propertiesChanged.begin()->second);
891 }
892 catch (std::exception& e)
893 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800894 phosphor::logging::log<phosphor::logging::level::ERR>(
895 "Unable to read power restore policy value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700896 powerRestorePolicyMatch.reset();
897 return;
898 }
899 invokePowerRestorePolicy(policy);
900 powerRestorePolicyMatch.reset();
901 });
902
903 // Check if it's already on DBus
904 conn->async_method_call(
905 [](boost::system::error_code ec,
906 const std::variant<std::string>& policyProperty) {
907 if (ec)
908 {
909 return;
910 }
911 powerRestorePolicyMatch.reset();
912 const std::string* policy =
913 std::get_if<std::string>(&policyProperty);
914 if (policy == nullptr)
915 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800916 phosphor::logging::log<phosphor::logging::level::ERR>(
917 "Unable to read power restore policy value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700918 return;
919 }
920 invokePowerRestorePolicy(*policy);
921 },
922 "xyz.openbmc_project.Settings",
923 "/xyz/openbmc_project/control/host0/power_restore_policy",
924 "org.freedesktop.DBus.Properties", "Get",
925 "xyz.openbmc_project.Control.Power.RestorePolicy",
926 "PowerRestorePolicy");
927 });
928}
929
930static void powerRestorePolicyStart()
931{
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800932 phosphor::logging::log<phosphor::logging::level::INFO>(
933 "Power restore policy started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700934 powerRestorePolicyLog();
935
936 // Get the desired delay time
937 // In case PowerRestoreDelay is not available, set a match for it
938 static std::unique_ptr<sdbusplus::bus::match::match>
939 powerRestoreDelayMatch = std::make_unique<sdbusplus::bus::match::match>(
940 *conn,
941 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
942 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Control."
943 "Power.RestoreDelay'",
944 [](sdbusplus::message::message& msg) {
945 std::string interfaceName;
946 boost::container::flat_map<std::string, std::variant<uint16_t>>
947 propertiesChanged;
948 int delay = 0;
949 try
950 {
951 msg.read(interfaceName, propertiesChanged);
952 delay =
953 std::get<uint16_t>(propertiesChanged.begin()->second);
954 }
955 catch (std::exception& e)
956 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800957 phosphor::logging::log<phosphor::logging::level::ERR>(
958 "Unable to read power restore delay value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700959 powerRestoreDelayMatch.reset();
960 return;
961 }
962 powerRestorePolicyDelay(delay);
963 powerRestoreDelayMatch.reset();
964 });
965
966 // Check if it's already on DBus
967 conn->async_method_call(
968 [](boost::system::error_code ec,
969 const std::variant<uint16_t>& delayProperty) {
970 if (ec)
971 {
972 return;
973 }
974 powerRestoreDelayMatch.reset();
975 const uint16_t* delay = std::get_if<uint16_t>(&delayProperty);
976 if (delay == nullptr)
977 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800978 phosphor::logging::log<phosphor::logging::level::ERR>(
979 "Unable to read power restore delay value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700980 return;
981 }
982 powerRestorePolicyDelay(*delay);
983 },
984 "xyz.openbmc_project.Settings",
985 "/xyz/openbmc_project/control/power_restore_delay",
986 "org.freedesktop.DBus.Properties", "Get",
987 "xyz.openbmc_project.Control.Power.RestoreDelay", "PowerRestoreDelay");
988}
989
990static void powerRestorePolicyCheck()
991{
992 // In case ACBoot is not available, set a match for it
993 static std::unique_ptr<sdbusplus::bus::match::match> acBootMatch =
994 std::make_unique<sdbusplus::bus::match::match>(
995 *conn,
996 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
997 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Common."
998 "ACBoot'",
999 [](sdbusplus::message::message& msg) {
1000 std::string interfaceName;
1001 boost::container::flat_map<std::string,
1002 std::variant<std::string>>
1003 propertiesChanged;
1004 std::string acBoot;
1005 try
1006 {
1007 msg.read(interfaceName, propertiesChanged);
1008 acBoot = std::get<std::string>(
1009 propertiesChanged.begin()->second);
1010 }
1011 catch (std::exception& e)
1012 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001013 phosphor::logging::log<phosphor::logging::level::ERR>(
1014 "Unable to read AC Boot status");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001015 acBootMatch.reset();
1016 return;
1017 }
1018 if (acBoot == "Unknown")
1019 {
1020 return;
1021 }
1022 if (acBoot == "True")
1023 {
1024 // Start the Power Restore policy
1025 powerRestorePolicyStart();
1026 }
1027 acBootMatch.reset();
1028 });
1029
1030 // Check if it's already on DBus
1031 conn->async_method_call(
1032 [](boost::system::error_code ec,
1033 const std::variant<std::string>& acBootProperty) {
1034 if (ec)
1035 {
1036 return;
1037 }
1038 const std::string* acBoot =
1039 std::get_if<std::string>(&acBootProperty);
1040 if (acBoot == nullptr)
1041 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001042 phosphor::logging::log<phosphor::logging::level::ERR>(
1043 "Unable to read AC Boot status");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001044 return;
1045 }
1046 if (*acBoot == "Unknown")
1047 {
1048 return;
1049 }
1050 if (*acBoot == "True")
1051 {
1052 // Start the Power Restore policy
1053 powerRestorePolicyStart();
1054 }
1055 acBootMatch.reset();
1056 },
1057 "xyz.openbmc_project.Settings",
1058 "/xyz/openbmc_project/control/host0/ac_boot",
1059 "org.freedesktop.DBus.Properties", "Get",
1060 "xyz.openbmc_project.Common.ACBoot", "ACBoot");
1061}
1062
1063static bool requestGPIOEvents(
1064 const std::string& name, const std::function<void()>& handler,
1065 gpiod::line& gpioLine,
1066 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
1067{
1068 // Find the GPIO line
1069 gpioLine = gpiod::find_line(name);
1070 if (!gpioLine)
1071 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001072 std::string errMsg = "Failed to find the " + name + " line";
1073 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001074 return false;
1075 }
1076
1077 try
1078 {
1079 gpioLine.request(
1080 {"power-control", gpiod::line_request::EVENT_BOTH_EDGES});
1081 }
1082 catch (std::exception&)
1083 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001084 std::string errMsg = "Failed to request events for " + name;
1085 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001086 return false;
1087 }
1088
1089 int gpioLineFd = gpioLine.event_get_fd();
1090 if (gpioLineFd < 0)
1091 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001092 std::string errMsg = "Failed to name " + name + " fd";
1093 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001094 return false;
1095 }
1096
1097 gpioEventDescriptor.assign(gpioLineFd);
1098
1099 gpioEventDescriptor.async_wait(
1100 boost::asio::posix::stream_descriptor::wait_read,
1101 [&name, handler](const boost::system::error_code ec) {
1102 if (ec)
1103 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001104 std::string errMsg =
1105 name + " fd handler error: " + ec.message();
1106 phosphor::logging::log<phosphor::logging::level::ERR>(
1107 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001108 // TODO: throw here to force power-control to restart?
1109 return;
1110 }
1111 handler();
1112 });
1113 return true;
1114}
1115
1116static bool setGPIOOutput(const std::string& name, const int value,
1117 gpiod::line& gpioLine)
1118{
1119 // Find the GPIO line
1120 gpioLine = gpiod::find_line(name);
1121 if (!gpioLine)
1122 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001123 std::string errMsg = "Failed to find the " + name + " line";
1124 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001125 return false;
1126 }
1127
1128 // Request GPIO output to specified value
1129 try
1130 {
1131 gpioLine.request({__FUNCTION__, gpiod::line_request::DIRECTION_OUTPUT},
1132 value);
1133 }
1134 catch (std::exception&)
1135 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001136 std::string errMsg = "Failed to request " + name + " output";
1137 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001138 return false;
1139 }
1140
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001141 std::string logMsg = name + " set to " + std::to_string(value);
1142 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001143 return true;
1144}
1145
1146static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1147 const std::string& name, const int value,
1148 const int durationMs)
1149{
1150 // Set the masked GPIO line to the specified value
1151 maskedGPIOLine.set_value(value);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001152 std::string logMsg = name + " set to " + std::to_string(value);
1153 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001154 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001155 gpioAssertTimer.async_wait([maskedGPIOLine, value,
1156 name](const boost::system::error_code ec) {
1157 // Set the masked GPIO line back to the opposite value
1158 maskedGPIOLine.set_value(!value);
1159 std::string logMsg = name + " released";
1160 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
1161 if (ec)
1162 {
1163 // operation_aborted is expected if timer is canceled before
1164 // completion.
1165 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001166 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001167 std::string errMsg =
1168 name + " async_wait failed: " + ec.message();
1169 phosphor::logging::log<phosphor::logging::level::ERR>(
1170 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001171 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001172 }
1173 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001174 return 0;
1175}
1176
1177static int setGPIOOutputForMs(const std::string& name, const int value,
1178 const int durationMs)
1179{
1180 // If the requested GPIO is masked, use the mask line to set the output
Priyatharshan P70120512020-09-16 18:47:20 +05301181 if (powerButtonMask && name == powerOutConfig.lineName)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001182 {
1183 return setMaskedGPIOOutputForMs(powerButtonMask, name, value,
1184 durationMs);
1185 }
Priyatharshan P70120512020-09-16 18:47:20 +05301186 if (resetButtonMask && name == resetOutConfig.lineName)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001187 {
1188 return setMaskedGPIOOutputForMs(resetButtonMask, name, value,
1189 durationMs);
1190 }
1191
1192 // No mask set, so request and set the GPIO normally
1193 gpiod::line gpioLine;
1194 if (!setGPIOOutput(name, value, gpioLine))
1195 {
1196 return -1;
1197 }
1198 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001199 gpioAssertTimer.async_wait([gpioLine, value,
1200 name](const boost::system::error_code ec) {
1201 // Set the GPIO line back to the opposite value
1202 gpioLine.set_value(!value);
1203 std::string logMsg = name + " released";
1204 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
1205 if (ec)
1206 {
1207 // operation_aborted is expected if timer is canceled before
1208 // completion.
1209 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001210 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001211 std::string errMsg =
1212 name + " async_wait failed: " + ec.message();
1213 phosphor::logging::log<phosphor::logging::level::ERR>(
1214 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001215 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001216 }
1217 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001218 return 0;
1219}
1220
1221static void powerOn()
1222{
Priyatharshan P70120512020-09-16 18:47:20 +05301223 setGPIOOutputForMs(powerOutConfig.lineName, 0,
1224 TimerMap["powerPulseTimeMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001225}
Naveen Moses117c34e2021-05-26 20:10:51 +05301226#ifdef CHASSIS_SYSTEM_RESET
1227static int slotPowerOn()
1228{
1229 if (power_control::slotPowerState != power_control::SlotPowerState::on)
1230 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001231
Naveen Moses117c34e2021-05-26 20:10:51 +05301232 slotPowerLine.set_value(1);
1233
1234 if (slotPowerLine.get_value() > 0)
1235 {
1236 setSlotPowerState(SlotPowerState::on);
1237 phosphor::logging::log<phosphor::logging::level::INFO>(
1238 "Slot Power is switched On\n");
1239 }
1240 else
1241 {
1242 return -1;
1243 }
1244 }
1245 else
1246 {
1247 phosphor::logging::log<phosphor::logging::level::INFO>(
1248 "Slot Power is already in 'On' state\n");
1249 return -1;
1250 }
1251 return 0;
1252}
1253static int slotPowerOff()
1254{
1255 if (power_control::slotPowerState != power_control::SlotPowerState::off)
1256 {
1257 slotPowerLine.set_value(0);
1258
1259 if (!(slotPowerLine.get_value() > 0))
1260 {
1261 setSlotPowerState(SlotPowerState::off);
1262 setPowerState(PowerState::off);
1263 phosphor::logging::log<phosphor::logging::level::INFO>(
1264 "Slot Power is switched Off\n");
1265 }
1266 else
1267 {
1268 return -1;
1269 }
1270 }
1271 else
1272 {
1273 phosphor::logging::log<phosphor::logging::level::INFO>(
1274 "Slot Power is already in 'Off' state\n");
1275 return -1;
1276 }
1277 return 0;
1278}
1279static void slotPowerCycle()
1280{
1281 phosphor::logging::log<phosphor::logging::level::INFO>(
1282 "Slot Power Cycle started\n");
1283 slotPowerOff();
1284 slotPowerCycleTimer.expires_after(
1285 std::chrono::milliseconds(TimerMap["slotPowerCycleTimeMs"]));
1286 slotPowerCycleTimer.async_wait([](const boost::system::error_code ec) {
1287 if (ec)
1288 {
1289 if (ec != boost::asio::error::operation_aborted)
1290 {
1291 std::string errMsg =
1292 "Slot Power cycle timer async_wait failed: " + ec.message();
1293 phosphor::logging::log<phosphor::logging::level::ERR>(
1294 errMsg.c_str());
1295 }
1296 phosphor::logging::log<phosphor::logging::level::INFO>(
1297 "Slot Power cycle timer canceled\n");
1298 return;
1299 }
1300 phosphor::logging::log<phosphor::logging::level::INFO>(
1301 "Slot Power cycle timer completed\n");
1302 slotPowerOn();
1303 phosphor::logging::log<phosphor::logging::level::INFO>(
1304 "Slot Power Cycle Completed\n");
1305 });
1306}
1307#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001308static void gracefulPowerOff()
1309{
Priyatharshan P70120512020-09-16 18:47:20 +05301310 setGPIOOutputForMs(powerOutConfig.lineName, 0,
1311 TimerMap["powerPulseTimeMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001312}
1313
1314static void forcePowerOff()
1315{
Priyatharshan P70120512020-09-16 18:47:20 +05301316 if (setGPIOOutputForMs(powerOutConfig.lineName, 0,
1317 TimerMap["forceOffPulseTimeMs"]) < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001318 {
1319 return;
1320 }
1321
1322 // If the force off timer expires, then the PCH power-button override
1323 // failed, so attempt the Unconditional Powerdown SMBus command.
1324 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1325 if (ec)
1326 {
1327 // operation_aborted is expected if timer is canceled before
1328 // completion.
1329 if (ec != boost::asio::error::operation_aborted)
1330 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001331 std::string errMsg =
1332 "Force power off async_wait failed: " + ec.message();
1333 phosphor::logging::log<phosphor::logging::level::ERR>(
1334 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001335 }
1336 return;
1337 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001338
1339 phosphor::logging::log<phosphor::logging::level::INFO>(
1340 "PCH Power-button override failed. Issuing Unconditional Powerdown "
1341 "SMBus command.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001342 const static constexpr size_t pchDevBusAddress = 3;
1343 const static constexpr size_t pchDevSlaveAddress = 0x44;
1344 const static constexpr size_t pchCmdReg = 0;
1345 const static constexpr size_t pchPowerDownCmd = 0x02;
1346 if (i2cSet(pchDevBusAddress, pchDevSlaveAddress, pchCmdReg,
1347 pchPowerDownCmd) < 0)
1348 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001349 phosphor::logging::log<phosphor::logging::level::ERR>(
1350 "Unconditional Powerdown command failed! Not sure what to do "
1351 "now.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001352 }
1353 });
1354}
1355
1356static void reset()
1357{
Priyatharshan P70120512020-09-16 18:47:20 +05301358 setGPIOOutputForMs(resetOutConfig.lineName, 0,
1359 TimerMap["resetPulseTimeMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001360}
1361
1362static void gracefulPowerOffTimerStart()
1363{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001364 phosphor::logging::log<phosphor::logging::level::INFO>(
1365 "Graceful power-off timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001366 gracefulPowerOffTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301367 std::chrono::seconds(TimerMap["gracefulPowerOffTimeS"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001368 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1369 if (ec)
1370 {
1371 // operation_aborted is expected if timer is canceled before
1372 // completion.
1373 if (ec != boost::asio::error::operation_aborted)
1374 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001375 std::string errMsg =
1376 "Graceful power-off async_wait failed: " + ec.message();
1377 phosphor::logging::log<phosphor::logging::level::ERR>(
1378 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001379 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001380 phosphor::logging::log<phosphor::logging::level::INFO>(
1381 "Graceful power-off timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001382 return;
1383 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001384 phosphor::logging::log<phosphor::logging::level::INFO>(
1385 "Graceful power-off timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001386 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1387 });
1388}
1389
1390static void powerCycleTimerStart()
1391{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001392 phosphor::logging::log<phosphor::logging::level::INFO>(
1393 "Power-cycle timer started");
Priyatharshan P70120512020-09-16 18:47:20 +05301394 powerCycleTimer.expires_after(
1395 std::chrono::milliseconds(TimerMap["powerCycleTimeMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001396 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1397 if (ec)
1398 {
1399 // operation_aborted is expected if timer is canceled before
1400 // completion.
1401 if (ec != boost::asio::error::operation_aborted)
1402 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001403 std::string errMsg =
1404 "Power-cycle async_wait failed: " + ec.message();
1405 phosphor::logging::log<phosphor::logging::level::ERR>(
1406 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001407 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001408 phosphor::logging::log<phosphor::logging::level::INFO>(
1409 "Power-cycle timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001410 return;
1411 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001412 phosphor::logging::log<phosphor::logging::level::INFO>(
1413 "Power-cycle timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001414 sendPowerControlEvent(Event::powerCycleTimerExpired);
1415 });
1416}
1417
1418static void psPowerOKWatchdogTimerStart()
1419{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001420 phosphor::logging::log<phosphor::logging::level::INFO>(
1421 "power supply power OK watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001422 psPowerOKWatchdogTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301423 std::chrono::milliseconds(TimerMap["psPowerOKWatchdogTimeMs"]));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001424 psPowerOKWatchdogTimer.async_wait([](const boost::system::error_code ec) {
1425 if (ec)
1426 {
1427 // operation_aborted is expected if timer is canceled before
1428 // completion.
1429 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001430 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001431 std::string errMsg =
1432 "power supply power OK watchdog async_wait failed: " +
1433 ec.message();
1434 phosphor::logging::log<phosphor::logging::level::ERR>(
1435 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001436 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001437 phosphor::logging::log<phosphor::logging::level::INFO>(
1438 "power supply power OK watchdog timer canceled");
1439 return;
1440 }
1441 phosphor::logging::log<phosphor::logging::level::INFO>(
1442 "power supply power OK watchdog timer expired");
1443 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1444 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001445}
1446
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001447static void warmResetCheckTimerStart()
1448{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001449 phosphor::logging::log<phosphor::logging::level::INFO>(
1450 "Warm reset check timer started");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001451 warmResetCheckTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301452 std::chrono::milliseconds(TimerMap["warmResetCheckTimeMs"]));
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001453 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1454 if (ec)
1455 {
1456 // operation_aborted is expected if timer is canceled before
1457 // completion.
1458 if (ec != boost::asio::error::operation_aborted)
1459 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001460 std::string errMsg =
1461 "Warm reset check async_wait failed: " + ec.message();
1462 phosphor::logging::log<phosphor::logging::level::ERR>(
1463 errMsg.c_str());
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001464 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001465 phosphor::logging::log<phosphor::logging::level::INFO>(
1466 "Warm reset check timer canceled");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001467 return;
1468 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001469 phosphor::logging::log<phosphor::logging::level::INFO>(
1470 "Warm reset check timer completed");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001471 sendPowerControlEvent(Event::warmResetDetected);
1472 });
1473}
1474
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001475static void pohCounterTimerStart()
1476{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001477 phosphor::logging::log<phosphor::logging::level::INFO>("POH timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001478 // Set the time-out as 1 hour, to align with POH command in ipmid
1479 pohCounterTimer.expires_after(std::chrono::hours(1));
1480 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1481 if (ec)
1482 {
1483 // operation_aborted is expected if timer is canceled before
1484 // completion.
1485 if (ec != boost::asio::error::operation_aborted)
1486 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001487 std::string errMsg =
1488 "POH timer async_wait failed: " + ec.message();
1489 phosphor::logging::log<phosphor::logging::level::ERR>(
1490 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001491 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001492 phosphor::logging::log<phosphor::logging::level::INFO>(
1493 "POH timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001494 return;
1495 }
1496
1497 if (getHostState(powerState) !=
1498 "xyz.openbmc_project.State.Host.HostState.Running")
1499 {
1500 return;
1501 }
1502
1503 conn->async_method_call(
1504 [](boost::system::error_code ec,
1505 const std::variant<uint32_t>& pohCounterProperty) {
1506 if (ec)
1507 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001508 phosphor::logging::log<phosphor::logging::level::INFO>(
1509 "error to get poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001510 return;
1511 }
1512 const uint32_t* pohCounter =
1513 std::get_if<uint32_t>(&pohCounterProperty);
1514 if (pohCounter == nullptr)
1515 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001516 phosphor::logging::log<phosphor::logging::level::INFO>(
1517 "unable to read poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001518 return;
1519 }
1520
1521 conn->async_method_call(
1522 [](boost::system::error_code ec) {
1523 if (ec)
1524 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001525 phosphor::logging::log<
1526 phosphor::logging::level::INFO>(
1527 "failed to set poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001528 }
1529 },
1530 "xyz.openbmc_project.Settings",
1531 "/xyz/openbmc_project/state/chassis0",
1532 "org.freedesktop.DBus.Properties", "Set",
1533 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1534 std::variant<uint32_t>(*pohCounter + 1));
1535 },
1536 "xyz.openbmc_project.Settings",
1537 "/xyz/openbmc_project/state/chassis0",
1538 "org.freedesktop.DBus.Properties", "Get",
1539 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1540
1541 pohCounterTimerStart();
1542 });
1543}
1544
1545static void currentHostStateMonitor()
1546{
Yong Li8d660212019-12-27 10:18:10 +08001547 if (getHostState(powerState) ==
1548 "xyz.openbmc_project.State.Host.HostState.Running")
1549 {
1550 pohCounterTimerStart();
1551 // Clear the restart cause set for the next restart
1552 clearRestartCause();
1553 }
1554 else
1555 {
1556 pohCounterTimer.cancel();
1557 // Set the restart cause set for this restart
1558 setRestartCause();
1559 }
1560
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001561 static auto match = sdbusplus::bus::match::match(
1562 *conn,
1563 "type='signal',member='PropertiesChanged', "
1564 "interface='org.freedesktop.DBus.Properties', "
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001565 "arg0='xyz.openbmc_project.State.Host'",
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001566 [](sdbusplus::message::message& message) {
1567 std::string intfName;
1568 std::map<std::string, std::variant<std::string>> properties;
1569
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001570 try
1571 {
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001572 message.read(intfName, properties);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001573 }
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001574 catch (std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001575 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001576 phosphor::logging::log<phosphor::logging::level::ERR>(
1577 "Unable to read host state");
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001578 return;
1579 }
1580 if (properties.empty())
1581 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001582 phosphor::logging::log<phosphor::logging::level::ERR>(
1583 "ERROR: Empty PropertiesChanged signal received");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001584 return;
1585 }
1586
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001587 // We only want to check for CurrentHostState
1588 if (properties.begin()->first != "CurrentHostState")
1589 {
1590 return;
1591 }
1592 std::string* currentHostState =
1593 std::get_if<std::string>(&(properties.begin()->second));
1594 if (currentHostState == nullptr)
1595 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001596 std::string errMsg =
1597 properties.begin()->first + " property invalid";
1598 phosphor::logging::log<phosphor::logging::level::ERR>(
1599 errMsg.c_str());
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001600 return;
1601 }
1602
1603 if (*currentHostState ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001604 "xyz.openbmc_project.State.Host.HostState.Running")
1605 {
1606 pohCounterTimerStart();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001607 // Clear the restart cause set for the next restart
1608 clearRestartCause();
Yong Li8d660212019-12-27 10:18:10 +08001609 sd_journal_send("MESSAGE=Host system DC power is on",
1610 "PRIORITY=%i", LOG_INFO,
1611 "REDFISH_MESSAGE_ID=%s",
1612 "OpenBMC.0.1.DCPowerOn", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001613 }
1614 else
1615 {
1616 pohCounterTimer.cancel();
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301617 // POST_COMPLETE GPIO event is not working in some platforms
1618 // when power state is changed to OFF. This resulted in
1619 // 'OperatingSystemState' to stay at 'Standby', even though
1620 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1621 // if HostState is trurned to OFF.
1622 osIface->set_property("OperatingSystemState",
1623 std::string("Inactive"));
1624
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001625 // Set the restart cause set for this restart
1626 setRestartCause();
Rashmi RV89f61312020-01-22 15:41:50 +05301627 resetACBootProperty();
Yong Li8d660212019-12-27 10:18:10 +08001628 sd_journal_send("MESSAGE=Host system DC power is off",
1629 "PRIORITY=%i", LOG_INFO,
1630 "REDFISH_MESSAGE_ID=%s",
1631 "OpenBMC.0.1.DCPowerOff", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001632 }
1633 });
1634}
1635
1636static void sioPowerGoodWatchdogTimerStart()
1637{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001638 phosphor::logging::log<phosphor::logging::level::INFO>(
1639 "SIO power good watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001640 sioPowerGoodWatchdogTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301641 std::chrono::milliseconds(TimerMap["sioPowerGoodWatchdogTimeMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001642 sioPowerGoodWatchdogTimer.async_wait(
1643 [](const boost::system::error_code ec) {
1644 if (ec)
1645 {
1646 // operation_aborted is expected if timer is canceled before
1647 // completion.
1648 if (ec != boost::asio::error::operation_aborted)
1649 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001650 std::string errMsg =
1651 "SIO power good watchdog async_wait failed: " +
1652 ec.message();
1653 phosphor::logging::log<phosphor::logging::level::ERR>(
1654 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001655 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001656 phosphor::logging::log<phosphor::logging::level::INFO>(
1657 "SIO power good watchdog timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001658 return;
1659 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001660 phosphor::logging::log<phosphor::logging::level::INFO>(
1661 "SIO power good watchdog timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001662 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1663 });
1664}
1665
1666static void powerStateOn(const Event event)
1667{
1668 logEvent(__FUNCTION__, event);
1669 switch (event)
1670 {
1671 case Event::psPowerOKDeAssert:
1672 setPowerState(PowerState::off);
1673 // DC power is unexpectedly lost, beep
1674 beep(beepPowerFail);
1675 break;
1676 case Event::sioS5Assert:
1677 setPowerState(PowerState::transitionToOff);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001678 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001679 break;
Jason M. Billsfb957332021-01-28 13:18:46 -08001680#if USE_PLT_RST
1681 case Event::pltRstAssert:
1682#else
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001683 case Event::postCompleteDeAssert:
Jason M. Billsfb957332021-01-28 13:18:46 -08001684#endif
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001685 setPowerState(PowerState::checkForWarmReset);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001686 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001687 warmResetCheckTimerStart();
1688 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001689 case Event::powerButtonPressed:
1690 setPowerState(PowerState::gracefulTransitionToOff);
1691 gracefulPowerOffTimerStart();
1692 break;
1693 case Event::powerOffRequest:
1694 setPowerState(PowerState::transitionToOff);
1695 forcePowerOff();
1696 break;
1697 case Event::gracefulPowerOffRequest:
1698 setPowerState(PowerState::gracefulTransitionToOff);
1699 gracefulPowerOffTimerStart();
1700 gracefulPowerOff();
1701 break;
1702 case Event::powerCycleRequest:
1703 setPowerState(PowerState::transitionToCycleOff);
1704 forcePowerOff();
1705 break;
1706 case Event::gracefulPowerCycleRequest:
1707 setPowerState(PowerState::gracefulTransitionToCycleOff);
1708 gracefulPowerOffTimerStart();
1709 gracefulPowerOff();
1710 break;
1711 case Event::resetRequest:
1712 reset();
1713 break;
1714 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001715 phosphor::logging::log<phosphor::logging::level::INFO>(
1716 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001717 break;
1718 }
1719}
1720
1721static void powerStateWaitForPSPowerOK(const Event event)
1722{
1723 logEvent(__FUNCTION__, event);
1724 switch (event)
1725 {
1726 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301727 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001728 // Cancel any GPIO assertions held during the transition
1729 gpioAssertTimer.cancel();
1730 psPowerOKWatchdogTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301731 if (sioEnabled == true)
1732 {
1733 sioPowerGoodWatchdogTimerStart();
1734 setPowerState(PowerState::waitForSIOPowerGood);
1735 }
1736 else
1737 {
1738 setPowerState(PowerState::on);
1739 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001740 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301741 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001742 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001743 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001744 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001745 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001746 case Event::sioPowerGoodAssert:
1747 psPowerOKWatchdogTimer.cancel();
1748 setPowerState(PowerState::on);
1749 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001750 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001751 phosphor::logging::log<phosphor::logging::level::INFO>(
1752 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001753 break;
1754 }
1755}
1756
1757static void powerStateWaitForSIOPowerGood(const Event event)
1758{
1759 logEvent(__FUNCTION__, event);
1760 switch (event)
1761 {
1762 case Event::sioPowerGoodAssert:
1763 sioPowerGoodWatchdogTimer.cancel();
1764 setPowerState(PowerState::on);
1765 break;
1766 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001767 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001768 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001769 break;
1770 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001771 phosphor::logging::log<phosphor::logging::level::INFO>(
1772 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001773 break;
1774 }
1775}
1776
1777static void powerStateOff(const Event event)
1778{
1779 logEvent(__FUNCTION__, event);
1780 switch (event)
1781 {
1782 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301783 {
1784 if (sioEnabled == true)
1785 {
1786 setPowerState(PowerState::waitForSIOPowerGood);
1787 }
1788 else
1789 {
1790 setPowerState(PowerState::on);
1791 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001792 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301793 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001794 case Event::sioS5DeAssert:
1795 setPowerState(PowerState::waitForPSPowerOK);
1796 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001797 case Event::sioPowerGoodAssert:
1798 setPowerState(PowerState::on);
1799 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001800 case Event::powerButtonPressed:
1801 psPowerOKWatchdogTimerStart();
1802 setPowerState(PowerState::waitForPSPowerOK);
1803 break;
1804 case Event::powerOnRequest:
1805 psPowerOKWatchdogTimerStart();
1806 setPowerState(PowerState::waitForPSPowerOK);
1807 powerOn();
1808 break;
1809 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001810 phosphor::logging::log<phosphor::logging::level::INFO>(
1811 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001812 break;
1813 }
1814}
1815
1816static void powerStateTransitionToOff(const Event event)
1817{
1818 logEvent(__FUNCTION__, event);
1819 switch (event)
1820 {
1821 case Event::psPowerOKDeAssert:
1822 // Cancel any GPIO assertions held during the transition
1823 gpioAssertTimer.cancel();
1824 setPowerState(PowerState::off);
1825 break;
1826 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001827 phosphor::logging::log<phosphor::logging::level::INFO>(
1828 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001829 break;
1830 }
1831}
1832
1833static void powerStateGracefulTransitionToOff(const Event event)
1834{
1835 logEvent(__FUNCTION__, event);
1836 switch (event)
1837 {
1838 case Event::psPowerOKDeAssert:
1839 gracefulPowerOffTimer.cancel();
1840 setPowerState(PowerState::off);
1841 break;
1842 case Event::gracefulPowerOffTimerExpired:
1843 setPowerState(PowerState::on);
1844 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001845 case Event::powerOffRequest:
1846 gracefulPowerOffTimer.cancel();
1847 setPowerState(PowerState::transitionToOff);
1848 forcePowerOff();
1849 break;
1850 case Event::powerCycleRequest:
1851 gracefulPowerOffTimer.cancel();
1852 setPowerState(PowerState::transitionToCycleOff);
1853 forcePowerOff();
1854 break;
1855 case Event::resetRequest:
1856 gracefulPowerOffTimer.cancel();
1857 setPowerState(PowerState::on);
1858 reset();
1859 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001860 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001861 phosphor::logging::log<phosphor::logging::level::INFO>(
1862 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001863 break;
1864 }
1865}
1866
1867static void powerStateCycleOff(const Event event)
1868{
1869 logEvent(__FUNCTION__, event);
1870 switch (event)
1871 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001872 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301873 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001874 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301875 if (sioEnabled == true)
1876 {
1877 setPowerState(PowerState::waitForSIOPowerGood);
1878 }
1879 else
1880 {
1881 setPowerState(PowerState::on);
1882 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001883 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301884 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001885 case Event::sioS5DeAssert:
1886 powerCycleTimer.cancel();
1887 setPowerState(PowerState::waitForPSPowerOK);
1888 break;
1889 case Event::powerButtonPressed:
1890 powerCycleTimer.cancel();
1891 psPowerOKWatchdogTimerStart();
1892 setPowerState(PowerState::waitForPSPowerOK);
1893 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001894 case Event::powerCycleTimerExpired:
1895 psPowerOKWatchdogTimerStart();
1896 setPowerState(PowerState::waitForPSPowerOK);
1897 powerOn();
1898 break;
1899 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001900 phosphor::logging::log<phosphor::logging::level::INFO>(
1901 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001902 break;
1903 }
1904}
1905
1906static void powerStateTransitionToCycleOff(const Event event)
1907{
1908 logEvent(__FUNCTION__, event);
1909 switch (event)
1910 {
1911 case Event::psPowerOKDeAssert:
1912 // Cancel any GPIO assertions held during the transition
1913 gpioAssertTimer.cancel();
1914 setPowerState(PowerState::cycleOff);
1915 powerCycleTimerStart();
1916 break;
1917 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001918 phosphor::logging::log<phosphor::logging::level::INFO>(
1919 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001920 break;
1921 }
1922}
1923
1924static void powerStateGracefulTransitionToCycleOff(const Event event)
1925{
1926 logEvent(__FUNCTION__, event);
1927 switch (event)
1928 {
1929 case Event::psPowerOKDeAssert:
1930 gracefulPowerOffTimer.cancel();
1931 setPowerState(PowerState::cycleOff);
1932 powerCycleTimerStart();
1933 break;
1934 case Event::gracefulPowerOffTimerExpired:
1935 setPowerState(PowerState::on);
1936 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001937 case Event::powerOffRequest:
1938 gracefulPowerOffTimer.cancel();
1939 setPowerState(PowerState::transitionToOff);
1940 forcePowerOff();
1941 break;
1942 case Event::powerCycleRequest:
1943 gracefulPowerOffTimer.cancel();
1944 setPowerState(PowerState::transitionToCycleOff);
1945 forcePowerOff();
1946 break;
1947 case Event::resetRequest:
1948 gracefulPowerOffTimer.cancel();
1949 setPowerState(PowerState::on);
1950 reset();
1951 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001952 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001953 phosphor::logging::log<phosphor::logging::level::INFO>(
1954 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001955 break;
1956 }
1957}
1958
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001959static void powerStateCheckForWarmReset(const Event event)
1960{
1961 logEvent(__FUNCTION__, event);
1962 switch (event)
1963 {
1964 case Event::sioS5Assert:
1965 warmResetCheckTimer.cancel();
1966 setPowerState(PowerState::transitionToOff);
1967 break;
1968 case Event::warmResetDetected:
1969 setPowerState(PowerState::on);
1970 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001971 case Event::psPowerOKDeAssert:
1972 warmResetCheckTimer.cancel();
1973 setPowerState(PowerState::off);
1974 // DC power is unexpectedly lost, beep
1975 beep(beepPowerFail);
1976 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001977 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001978 phosphor::logging::log<phosphor::logging::level::INFO>(
1979 "No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001980 break;
1981 }
1982}
1983
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001984static void psPowerOKHandler()
1985{
1986 gpiod::line_event gpioLineEvent = psPowerOKLine.event_read();
1987
1988 Event powerControlEvent =
1989 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
1990 ? Event::psPowerOKAssert
1991 : Event::psPowerOKDeAssert;
1992
1993 sendPowerControlEvent(powerControlEvent);
1994 psPowerOKEvent.async_wait(
1995 boost::asio::posix::stream_descriptor::wait_read,
1996 [](const boost::system::error_code ec) {
1997 if (ec)
1998 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001999 std::string errMsg =
2000 "power supply power OK handler error: " + ec.message();
2001 phosphor::logging::log<phosphor::logging::level::ERR>(
2002 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002003 return;
2004 }
2005 psPowerOKHandler();
2006 });
2007}
2008
2009static void sioPowerGoodHandler()
2010{
2011 gpiod::line_event gpioLineEvent = sioPowerGoodLine.event_read();
2012
2013 Event powerControlEvent =
2014 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
2015 ? Event::sioPowerGoodAssert
2016 : Event::sioPowerGoodDeAssert;
2017
2018 sendPowerControlEvent(powerControlEvent);
2019 sioPowerGoodEvent.async_wait(
2020 boost::asio::posix::stream_descriptor::wait_read,
2021 [](const boost::system::error_code ec) {
2022 if (ec)
2023 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002024 std::string errMsg =
2025 "SIO power good handler error: " + ec.message();
2026 phosphor::logging::log<phosphor::logging::level::ERR>(
2027 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002028 return;
2029 }
2030 sioPowerGoodHandler();
2031 });
2032}
2033
2034static void sioOnControlHandler()
2035{
2036 gpiod::line_event gpioLineEvent = sioOnControlLine.event_read();
2037
2038 bool sioOnControl =
2039 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE;
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002040 std::string logMsg =
2041 "SIO_ONCONTROL value changed: " + std::to_string(sioOnControl);
2042 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002043 sioOnControlEvent.async_wait(
2044 boost::asio::posix::stream_descriptor::wait_read,
2045 [](const boost::system::error_code ec) {
2046 if (ec)
2047 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002048 std::string errMsg =
2049 "SIO ONCONTROL handler error: " + ec.message();
2050 phosphor::logging::log<phosphor::logging::level::ERR>(
2051 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002052 return;
2053 }
2054 sioOnControlHandler();
2055 });
2056}
2057
2058static void sioS5Handler()
2059{
2060 gpiod::line_event gpioLineEvent = sioS5Line.event_read();
2061
2062 Event powerControlEvent =
2063 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE
2064 ? Event::sioS5Assert
2065 : Event::sioS5DeAssert;
2066
2067 sendPowerControlEvent(powerControlEvent);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002068 sioS5Event.async_wait(
2069 boost::asio::posix::stream_descriptor::wait_read,
2070 [](const boost::system::error_code ec) {
2071 if (ec)
2072 {
2073 std::string errMsg = "SIO S5 handler error: " + ec.message();
2074 phosphor::logging::log<phosphor::logging::level::ERR>(
2075 errMsg.c_str());
2076 return;
2077 }
2078 sioS5Handler();
2079 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002080}
2081
2082static void powerButtonHandler()
2083{
2084 gpiod::line_event gpioLineEvent = powerButtonLine.event_read();
2085
2086 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2087 {
2088 powerButtonPressLog();
2089 powerButtonIface->set_property("ButtonPressed", true);
2090 if (!powerButtonMask)
2091 {
2092 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002093 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002094 }
2095 else
2096 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002097 phosphor::logging::log<phosphor::logging::level::INFO>(
2098 "power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002099 }
2100 }
2101 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2102 {
2103 powerButtonIface->set_property("ButtonPressed", false);
2104 }
2105 powerButtonEvent.async_wait(
2106 boost::asio::posix::stream_descriptor::wait_read,
2107 [](const boost::system::error_code ec) {
2108 if (ec)
2109 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002110 std::string errMsg =
2111 "power button handler error: " + ec.message();
2112 phosphor::logging::log<phosphor::logging::level::ERR>(
2113 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002114 return;
2115 }
2116 powerButtonHandler();
2117 });
2118}
2119
2120static void resetButtonHandler()
2121{
2122 gpiod::line_event gpioLineEvent = resetButtonLine.event_read();
2123
2124 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2125 {
2126 resetButtonPressLog();
2127 resetButtonIface->set_property("ButtonPressed", true);
2128 if (!resetButtonMask)
2129 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002130 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002131 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002132 }
2133 else
2134 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002135 phosphor::logging::log<phosphor::logging::level::INFO>(
2136 "reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002137 }
2138 }
2139 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2140 {
2141 resetButtonIface->set_property("ButtonPressed", false);
2142 }
2143 resetButtonEvent.async_wait(
2144 boost::asio::posix::stream_descriptor::wait_read,
2145 [](const boost::system::error_code ec) {
2146 if (ec)
2147 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002148 std::string errMsg =
2149 "reset button handler error: " + ec.message();
2150 phosphor::logging::log<phosphor::logging::level::ERR>(
2151 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002152 return;
2153 }
2154 resetButtonHandler();
2155 });
2156}
2157
Vijay Khemka04175c22020-10-09 14:28:11 -07002158#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002159static constexpr auto systemdBusname = "org.freedesktop.systemd1";
2160static constexpr auto systemdPath = "/org/freedesktop/systemd1";
2161static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
2162static constexpr auto systemTargetName = "chassis-system-reset.target";
2163
2164void systemReset()
2165{
2166 conn->async_method_call(
2167 [](boost::system::error_code ec) {
2168 if (ec)
2169 {
2170 phosphor::logging::log<phosphor::logging::level::ERR>(
2171 "Failed to call chassis system reset",
2172 phosphor::logging::entry("ERR=%s", ec.message().c_str()));
2173 }
2174 },
2175 systemdBusname, systemdPath, systemdInterface, "StartUnit",
2176 systemTargetName, "replace");
2177}
Vijay Khemka04175c22020-10-09 14:28:11 -07002178#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002179
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002180static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002181{
2182 conn->async_method_call(
2183 [](boost::system::error_code ec) {
2184 if (ec)
2185 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002186 phosphor::logging::log<phosphor::logging::level::INFO>(
2187 "failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002188 }
2189 },
Chen Yugang303bd582019-11-01 08:45:06 +08002190 "xyz.openbmc_project.Settings",
2191 "/xyz/openbmc_project/Chassis/Control/NMISource",
2192 "org.freedesktop.DBus.Properties", "Set",
2193 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
2194 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002195}
2196
2197static void nmiReset(void)
2198{
2199 static constexpr const uint8_t value = 1;
2200 const static constexpr int nmiOutPulseTimeMs = 200;
2201
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002202 phosphor::logging::log<phosphor::logging::level::INFO>("NMI out action");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002203 nmiOutLine.set_value(value);
Priyatharshan P70120512020-09-16 18:47:20 +05302204 std::string logMsg =
2205 nmiOutConfig.lineName + " set to " + std::to_string(value);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002206 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002207 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2208 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2209 // restore the NMI_OUT GPIO line back to the opposite value
2210 nmiOutLine.set_value(!value);
Priyatharshan P70120512020-09-16 18:47:20 +05302211 std::string logMsg = nmiOutConfig.lineName + " released";
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002212 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002213 if (ec)
2214 {
2215 // operation_aborted is expected if timer is canceled before
2216 // completion.
2217 if (ec != boost::asio::error::operation_aborted)
2218 {
Priyatharshan P70120512020-09-16 18:47:20 +05302219 std::string errMsg = nmiOutConfig.lineName +
2220 " async_wait failed: " + ec.message();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002221 phosphor::logging::log<phosphor::logging::level::ERR>(
2222 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002223 }
2224 }
2225 });
2226 // log to redfish
2227 nmiDiagIntLog();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002228 phosphor::logging::log<phosphor::logging::level::INFO>(
2229 "NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002230 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002231 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002232}
2233
2234static void nmiSourcePropertyMonitor(void)
2235{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002236 phosphor::logging::log<phosphor::logging::level::INFO>(
2237 "NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002238
2239 static std::unique_ptr<sdbusplus::bus::match::match> nmiSourceMatch =
2240 std::make_unique<sdbusplus::bus::match::match>(
2241 *conn,
2242 "type='signal',interface='org.freedesktop.DBus.Properties',"
Chen Yugang303bd582019-11-01 08:45:06 +08002243 "member='PropertiesChanged',arg0namespace='xyz.openbmc_project."
2244 "Chassis.Control."
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002245 "NMISource'",
2246 [](sdbusplus::message::message& msg) {
2247 std::string interfaceName;
2248 boost::container::flat_map<std::string,
2249 std::variant<bool, std::string>>
2250 propertiesChanged;
2251 std::string state;
2252 bool value = true;
2253 try
2254 {
2255 msg.read(interfaceName, propertiesChanged);
2256 if (propertiesChanged.begin()->first == "Enabled")
2257 {
2258 value =
2259 std::get<bool>(propertiesChanged.begin()->second);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002260 std::string logMsg =
2261 " NMI Enabled propertiesChanged value: " +
2262 std::to_string(value);
2263 phosphor::logging::log<phosphor::logging::level::INFO>(
2264 logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002265 nmiEnabled = value;
2266 if (nmiEnabled)
2267 {
2268 nmiReset();
2269 }
2270 }
2271 }
2272 catch (std::exception& e)
2273 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002274 phosphor::logging::log<phosphor::logging::level::ERR>(
2275 "Unable to read NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002276 return;
2277 }
2278 });
2279}
2280
2281static void setNmiSource()
2282{
2283 conn->async_method_call(
2284 [](boost::system::error_code ec) {
2285 if (ec)
2286 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002287 phosphor::logging::log<phosphor::logging::level::ERR>(
2288 "failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002289 }
2290 },
Chen Yugang303bd582019-11-01 08:45:06 +08002291 "xyz.openbmc_project.Settings",
2292 "/xyz/openbmc_project/Chassis/Control/NMISource",
2293 "org.freedesktop.DBus.Properties", "Set",
2294 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
2295 std::variant<std::string>{"xyz.openbmc_project.Chassis.Control."
2296 "NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002297 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002298 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002299}
2300
2301static void nmiButtonHandler()
2302{
2303 gpiod::line_event gpioLineEvent = nmiButtonLine.event_read();
2304
2305 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2306 {
2307 nmiButtonPressLog();
2308 nmiButtonIface->set_property("ButtonPressed", true);
2309 if (nmiButtonMasked)
2310 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002311 phosphor::logging::log<phosphor::logging::level::INFO>(
2312 "NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002313 }
2314 else
2315 {
2316 setNmiSource();
2317 }
2318 }
2319 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2320 {
2321 nmiButtonIface->set_property("ButtonPressed", false);
2322 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002323 nmiButtonEvent.async_wait(
2324 boost::asio::posix::stream_descriptor::wait_read,
2325 [](const boost::system::error_code ec) {
2326 if (ec)
2327 {
2328 std::string errMsg =
2329 "NMI button handler error: " + ec.message();
2330 phosphor::logging::log<phosphor::logging::level::ERR>(
2331 errMsg.c_str());
2332 return;
2333 }
2334 nmiButtonHandler();
2335 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002336}
2337
2338static void idButtonHandler()
2339{
2340 gpiod::line_event gpioLineEvent = idButtonLine.event_read();
2341
2342 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2343 {
2344 idButtonIface->set_property("ButtonPressed", true);
2345 }
2346 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2347 {
2348 idButtonIface->set_property("ButtonPressed", false);
2349 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002350 idButtonEvent.async_wait(
2351 boost::asio::posix::stream_descriptor::wait_read,
2352 [](const boost::system::error_code& ec) {
2353 if (ec)
2354 {
2355 std::string errMsg = "ID button handler error: " + ec.message();
2356 phosphor::logging::log<phosphor::logging::level::ERR>(
2357 errMsg.c_str());
2358 return;
2359 }
2360 idButtonHandler();
2361 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002362}
2363
Jason M. Billsfb957332021-01-28 13:18:46 -08002364static void pltRstHandler(bool pltRst)
2365{
2366 if (pltRst)
2367 {
2368 sendPowerControlEvent(Event::pltRstDeAssert);
2369 }
2370 else
2371 {
2372 sendPowerControlEvent(Event::pltRstAssert);
2373 }
2374}
2375
2376static void hostMiscHandler(sdbusplus::message::message& msg)
2377{
2378 std::string interfaceName;
2379 boost::container::flat_map<std::string, std::variant<bool>>
2380 propertiesChanged;
2381 bool pltRst;
2382 try
2383 {
2384 msg.read(interfaceName, propertiesChanged);
2385 }
2386 catch (std::exception& e)
2387 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002388 phosphor::logging::log<phosphor::logging::level::ERR>(
2389 "Unable to read Host Misc status");
Jason M. Billsfb957332021-01-28 13:18:46 -08002390 return;
2391 }
2392 if (propertiesChanged.empty())
2393 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002394 phosphor::logging::log<phosphor::logging::level::ERR>(
2395 "ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002396 return;
2397 }
2398
2399 for (auto& [property, value] : propertiesChanged)
2400 {
2401 if (property == "ESpiPlatformReset")
2402 {
2403 bool* pltRst = std::get_if<bool>(&value);
2404 if (pltRst == nullptr)
2405 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002406 std::string errMsg = property + " property invalid";
2407 phosphor::logging::log<phosphor::logging::level::ERR>(
2408 errMsg.c_str());
Jason M. Billsfb957332021-01-28 13:18:46 -08002409 return;
2410 }
2411 pltRstHandler(*pltRst);
2412 }
2413 }
2414}
2415
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002416static void postCompleteHandler()
2417{
2418 gpiod::line_event gpioLineEvent = postCompleteLine.event_read();
2419
2420 bool postComplete =
2421 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002422 if (postComplete)
2423 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002424 sendPowerControlEvent(Event::postCompleteAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002425 osIface->set_property("OperatingSystemState", std::string("Standby"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002426 }
2427 else
2428 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002429 sendPowerControlEvent(Event::postCompleteDeAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002430 osIface->set_property("OperatingSystemState", std::string("Inactive"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002431 }
2432 postCompleteEvent.async_wait(
2433 boost::asio::posix::stream_descriptor::wait_read,
2434 [](const boost::system::error_code ec) {
2435 if (ec)
2436 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002437 std::string errMsg =
2438 "POST complete handler error: " + ec.message();
2439 phosphor::logging::log<phosphor::logging::level::ERR>(
2440 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002441 return;
2442 }
2443 postCompleteHandler();
2444 });
2445}
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302446
2447static int loadConfigValues()
2448{
2449 const std::string configFilePath =
2450 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2451 ".json";
2452 std::ifstream configFile(configFilePath.c_str());
2453 if (!configFile.is_open())
2454 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002455 phosphor::logging::log<phosphor::logging::level::ERR>(
2456 "loadConfigValues : Cannot open config path");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302457 return -1;
2458 }
Priyatharshan P70120512020-09-16 18:47:20 +05302459 auto jsonData = nlohmann::json::parse(configFile, nullptr);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302460
Priyatharshan P70120512020-09-16 18:47:20 +05302461 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302462 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002463 phosphor::logging::log<phosphor::logging::level::ERR>(
2464 "Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302465 return -1;
2466 }
Priyatharshan P70120512020-09-16 18:47:20 +05302467 auto gpios = jsonData["gpio_configs"];
2468 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302469
Priyatharshan P70120512020-09-16 18:47:20 +05302470 ConfigData* tempGpioData;
2471
2472 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302473 {
Priyatharshan P70120512020-09-16 18:47:20 +05302474 if (!gpioConfig.contains("Name"))
2475 {
2476 phosphor::logging::log<phosphor::logging::level::ERR>(
2477 "The 'Name' field must be defined in Json file");
2478 return -1;
2479 }
2480
2481 // Iterate through the powersignal map to check if the gpio json config
2482 // entry is valid
2483 std::string gpioName = gpioConfig["Name"];
2484 auto signalMapIter = powerSignalMap.find(gpioName);
2485 if (signalMapIter == powerSignalMap.end())
2486 {
2487 std::string errMsg = "Undefined Name : " + gpioName;
2488 phosphor::logging::log<phosphor::logging::level::ERR>(
2489 errMsg.c_str());
2490 return -1;
2491 }
2492
2493 // assign the power signal name to the corresponding structure reference
2494 // from map then fillup the structure with coressponding json config
2495 // value
2496 tempGpioData = signalMapIter->second;
2497 tempGpioData->name = gpioName;
2498
2499 if (!gpioConfig.contains("Type"))
2500 {
2501 phosphor::logging::log<phosphor::logging::level::ERR>(
2502 "The \'Type\' field must be defined in Json file");
2503 return -1;
2504 }
2505
2506 std::string signalType = gpioConfig["Type"];
2507 if (signalType == "GPIO")
2508 {
2509 tempGpioData->type = ConfigType::GPIO;
2510 }
2511 else if (signalType == "DBUS")
2512 {
2513 tempGpioData->type = ConfigType::DBUS;
2514 }
2515 else
2516 {
2517 std::string errMsg = "Undefined Type : " + signalType;
2518 phosphor::logging::log<phosphor::logging::level::ERR>(
2519 errMsg.c_str());
2520 return -1;
2521 }
2522
2523 if (tempGpioData->type == ConfigType::GPIO)
2524 {
2525 if (gpioConfig.contains("LineName"))
2526 {
2527 tempGpioData->lineName = gpioConfig["LineName"];
2528 }
2529 else
2530 {
2531 phosphor::logging::log<phosphor::logging::level::ERR>(
2532 "The \'LineName\' field must be defined for GPIO "
2533 "configuration");
2534 return -1;
2535 }
2536 }
2537 else
2538 {
2539 // if dbus based gpio config is defined read and update the dbus
2540 // params corresponding to the gpio config instance
2541 for (auto& [key, dbusParamName] : dbusParams)
2542 {
2543 if (!gpios.contains(dbusParamName))
2544 {
2545 std::string errMsg =
2546 "The " + dbusParamName +
2547 "field must be defined for Dbus configuration ";
2548 phosphor::logging::log<phosphor::logging::level::ERR>(
2549 errMsg.c_str());
2550 return -1;
2551 }
2552 }
2553 tempGpioData->dbusName = gpios[dbusParams[DbusConfigType::name]];
2554 tempGpioData->path = gpios[dbusParams[DbusConfigType::path]];
2555 tempGpioData->interface =
2556 gpios[dbusParams[DbusConfigType::interface]];
2557 tempGpioData->lineName =
2558 gpios[dbusParams[DbusConfigType::property]];
2559 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302560 }
2561
Priyatharshan P70120512020-09-16 18:47:20 +05302562 // read and store the timer values from json config to Timer Map
2563 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302564 {
Priyatharshan P70120512020-09-16 18:47:20 +05302565 if (timers.contains(key.c_str()))
2566 {
2567 timerValue = timers[key.c_str()];
2568 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302569 }
2570
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302571 return 0;
2572}
Priyatharshan P70120512020-09-16 18:47:20 +05302573inline static sdbusplus::bus::match::match powerButtonEventMonitor()
2574{
2575 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2576 bool value = false;
2577 std::string thresholdInterface;
2578 std::string event;
2579 boost::container::flat_map<std::string, std::variant<bool>>
2580 propertiesChanged;
2581 try
2582 {
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302583
Priyatharshan P70120512020-09-16 18:47:20 +05302584 msg.read(thresholdInterface, propertiesChanged);
2585
2586 if (propertiesChanged.empty())
2587 {
2588 return;
2589 }
2590 event = propertiesChanged.begin()->first;
2591
2592 if (event.empty() || event != powerButtonConfig.lineName)
2593 {
2594 return;
2595 }
2596
2597 value = std::get<bool>(propertiesChanged.begin()->second);
2598 }
2599 catch (std::exception& e)
2600 {
2601 phosphor::logging::log<phosphor::logging::level::ERR>(
2602 "exception during reading dbus property : powerButtonConfig");
2603 return;
2604 }
2605
2606 if (value == false)
2607 {
2608 powerButtonPressLog();
2609 powerButtonIface->set_property("ButtonPressed", true);
2610 if (!powerButtonMask)
2611 {
2612 sendPowerControlEvent(Event::powerButtonPressed);
2613 addRestartCause(RestartCause::powerButton);
2614 }
2615 else
2616 {
2617 phosphor::logging::log<phosphor::logging::level::ERR>(
2618 "power button press masked\n");
2619 }
2620 }
2621 else
2622 {
2623 powerButtonIface->set_property("ButtonPressed", false);
2624 }
2625 };
2626
2627 sdbusplus::bus::match::match pulseEventMatcher(
2628 static_cast<sdbusplus::bus::bus&>(*conn),
2629 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2630 "PropertiesChanged',arg0='" +
2631 powerButtonConfig.dbusName + "'",
2632 std::move(pulseEventMatcherCallback));
2633
2634 return pulseEventMatcher;
2635}
2636
2637inline static sdbusplus::bus::match::match resetButtonEventMonitor()
2638{
2639 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2640 bool value = false;
2641 std::string thresholdInterface;
2642 std::string event;
2643 boost::container::flat_map<std::string, std::variant<bool>>
2644 propertiesChanged;
2645 try
2646 {
2647 msg.read(thresholdInterface, propertiesChanged);
2648
2649 if (propertiesChanged.empty())
2650 {
2651 return;
2652 }
2653 event = propertiesChanged.begin()->first;
2654
2655 if (event.empty() || event != resetButtonConfig.lineName)
2656 {
2657 return;
2658 }
2659
2660 value = std::get<bool>(propertiesChanged.begin()->second);
2661 }
2662 catch (std::exception& e)
2663 {
2664 phosphor::logging::log<phosphor::logging::level::ERR>(
2665 "exception during reading dbus property : resetButtonConfig");
2666 return;
2667 }
2668
2669 if (value == false)
2670 {
2671 resetButtonPressLog();
2672 resetButtonIface->set_property("ButtonPressed", true);
2673 if (!resetButtonMask)
2674 {
2675 sendPowerControlEvent(Event::resetButtonPressed);
2676 addRestartCause(RestartCause::resetButton);
2677 }
2678 else
2679 {
2680 phosphor::logging::log<phosphor::logging::level::ERR>(
2681 "reset button press masked");
2682 }
2683 }
2684 else
2685 {
2686 resetButtonIface->set_property("ButtonPressed", false);
2687 }
2688 };
2689
2690 sdbusplus::bus::match::match pulseEventMatcher(
2691 static_cast<sdbusplus::bus::bus&>(*conn),
2692 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2693 "PropertiesChanged',arg0='" +
2694 resetButtonConfig.dbusName + "'",
2695 std::move(pulseEventMatcherCallback));
2696
2697 return pulseEventMatcher;
2698}
2699
2700inline static sdbusplus::bus::match::match powerOkEventMonitor()
2701{
2702 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2703 bool value = false;
2704 std::string thresholdInterface;
2705 std::string event;
2706 boost::container::flat_map<std::string, std::variant<bool>>
2707 propertiesChanged;
2708 try
2709 {
2710 msg.read(thresholdInterface, propertiesChanged);
2711
2712 if (propertiesChanged.empty())
2713 {
2714 return;
2715 }
2716 event = propertiesChanged.begin()->first;
2717
2718 if (event.empty() || event != powerOkConfig.lineName)
2719 {
2720 return;
2721 }
2722
2723 value = std::get<bool>(propertiesChanged.begin()->second);
2724 }
2725 catch (std::exception& e)
2726 {
2727 phosphor::logging::log<phosphor::logging::level::ERR>(
2728 "exception during reading dbus property : powerOkConfig");
2729 return;
2730 }
2731
2732 Event powerControlEvent =
2733 value ? Event::psPowerOKAssert : Event::psPowerOKDeAssert;
2734 sendPowerControlEvent(powerControlEvent);
2735 };
2736
2737 sdbusplus::bus::match::match pulseEventMatcher(
2738 static_cast<sdbusplus::bus::bus&>(*conn),
2739 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2740 "PropertiesChanged',arg0='" +
2741 powerOkConfig.dbusName + "'",
2742 std::move(pulseEventMatcherCallback));
2743
2744 return pulseEventMatcher;
2745}
2746
2747inline static sdbusplus::bus::match::match sioPwrGoodEventMonitor()
2748{
2749 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2750 bool value = false;
2751 std::string thresholdInterface;
2752 std::string event;
2753 boost::container::flat_map<std::string, std::variant<bool>>
2754 propertiesChanged;
2755 try
2756 {
2757 msg.read(thresholdInterface, propertiesChanged);
2758
2759 if (propertiesChanged.empty())
2760 {
2761 return;
2762 }
2763 event = propertiesChanged.begin()->first;
2764
2765 if (event.empty() || event != sioPwrGoodConfig.lineName)
2766 {
2767 return;
2768 }
2769
2770 value = std::get<bool>(propertiesChanged.begin()->second);
2771 }
2772 catch (std::exception& e)
2773 {
2774 phosphor::logging::log<phosphor::logging::level::ERR>(
2775 "exception during reading dbus property : sioPwrGoodConfig");
2776 return;
2777 }
2778
2779 Event powerControlEvent =
2780 value ? Event::sioPowerGoodAssert : Event::sioPowerGoodDeAssert;
2781
2782 sendPowerControlEvent(powerControlEvent);
2783 };
2784
2785 sdbusplus::bus::match::match pulseEventMatcher(
2786 static_cast<sdbusplus::bus::bus&>(*conn),
2787 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2788 "PropertiesChanged',arg0='" +
2789 sioPwrGoodConfig.dbusName + "'",
2790 std::move(pulseEventMatcherCallback));
2791
2792 return pulseEventMatcher;
2793}
2794
2795inline static sdbusplus::bus::match::match sioOnControlEventMonitor()
2796{
2797 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2798 bool value = false;
2799 std::string thresholdInterface;
2800 std::string event;
2801 boost::container::flat_map<std::string, std::variant<bool>>
2802 propertiesChanged;
2803 try
2804 {
2805 msg.read(thresholdInterface, propertiesChanged);
2806
2807 if (propertiesChanged.empty())
2808 {
2809 return;
2810 }
2811 event = propertiesChanged.begin()->first;
2812
2813 if (event.empty() || event != sioOnControlConfig.lineName)
2814 {
2815 return;
2816 }
2817
2818 value = std::get<bool>(propertiesChanged.begin()->second);
2819 }
2820 catch (std::exception& e)
2821 {
2822 phosphor::logging::log<phosphor::logging::level::ERR>(
2823 "exception during reading dbus property : sioOnControlConfig");
2824 return;
2825 }
2826
2827 std::string errMsg =
2828 "SIO_ONCONTROL value changed : " + std::to_string(value);
2829 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
2830 };
2831
2832 sdbusplus::bus::match::match pulseEventMatcher(
2833 static_cast<sdbusplus::bus::bus&>(*conn),
2834 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2835 "PropertiesChanged',arg0='" +
2836 sioOnControlConfig.dbusName + "'",
2837 std::move(pulseEventMatcherCallback));
2838
2839 return pulseEventMatcher;
2840}
2841
2842inline static sdbusplus::bus::match::match sioS5EventMonitor()
2843{
2844 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2845 bool value = false;
2846 std::string thresholdInterface;
2847 std::string event;
2848 boost::container::flat_map<std::string, std::variant<bool>>
2849 propertiesChanged;
2850 try
2851 {
2852 msg.read(thresholdInterface, propertiesChanged);
2853
2854 if (propertiesChanged.empty())
2855 {
2856 return;
2857 }
2858 event = propertiesChanged.begin()->first;
2859
2860 if (event.empty() || event != sioS5Config.lineName)
2861 {
2862 return;
2863 }
2864
2865 value = std::get<bool>(propertiesChanged.begin()->second);
2866 }
2867 catch (std::exception& e)
2868 {
2869 phosphor::logging::log<phosphor::logging::level::ERR>(
2870 "exception during reading dbus property : sioS5Config");
2871 return;
2872 }
2873
2874 Event powerControlEvent =
2875 value ? Event::sioS5DeAssert : Event::sioS5Assert;
2876 sendPowerControlEvent(powerControlEvent);
2877 };
2878
2879 sdbusplus::bus::match::match pulseEventMatcher(
2880 static_cast<sdbusplus::bus::bus&>(*conn),
2881 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2882 "PropertiesChanged',arg0='" +
2883 sioS5Config.dbusName + "'",
2884 std::move(pulseEventMatcherCallback));
2885
2886 return pulseEventMatcher;
2887}
2888
2889inline static sdbusplus::bus::match::match nmiButtonEventMonitor()
2890{
2891 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2892 bool value = false;
2893 std::string thresholdInterface;
2894 std::string event;
2895 boost::container::flat_map<std::string, std::variant<bool>>
2896 propertiesChanged;
2897 try
2898 {
2899 msg.read(thresholdInterface, propertiesChanged);
2900
2901 if (propertiesChanged.empty())
2902 {
2903 return;
2904 }
2905 event = propertiesChanged.begin()->first;
2906 if (event.empty() || event != nmiButtonConfig.lineName)
2907 {
2908 return;
2909 }
2910
2911 value = std::get<bool>(propertiesChanged.begin()->second);
2912 }
2913 catch (std::exception& e)
2914 {
2915 phosphor::logging::log<phosphor::logging::level::ERR>(
2916 "exception during reading dbus property : nmiButtonConfig");
2917 return;
2918 }
2919
2920 if (value)
2921 {
2922 nmiButtonIface->set_property("ButtonPressed", false);
2923 }
2924 else
2925 {
2926 nmiButtonPressLog();
2927 nmiButtonIface->set_property("ButtonPressed", true);
2928 if (nmiButtonMasked)
2929 {
2930 phosphor::logging::log<phosphor::logging::level::ERR>(
2931 "NMI button press masked");
2932 }
2933 else
2934 {
2935 setNmiSource();
2936 }
2937 }
2938 };
2939
2940 sdbusplus::bus::match::match pulseEventMatcher(
2941 static_cast<sdbusplus::bus::bus&>(*conn),
2942 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2943 "PropertiesChanged',arg0='" +
2944 nmiButtonConfig.dbusName + "'",
2945 std::move(pulseEventMatcherCallback));
2946
2947 return pulseEventMatcher;
2948}
2949
2950inline static sdbusplus::bus::match::match idButtonEventMonitor()
2951{
2952 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2953 bool value = false;
2954 std::string thresholdInterface;
2955 std::string event;
2956 boost::container::flat_map<std::string, std::variant<bool>>
2957 propertiesChanged;
2958
2959 try
2960 {
2961
2962 msg.read(thresholdInterface, propertiesChanged);
2963
2964 if (propertiesChanged.empty())
2965 {
2966 return;
2967 }
2968 event = propertiesChanged.begin()->first;
2969
2970 if (event.empty() | event != idButtonConfig.lineName)
2971 {
2972 return;
2973 }
2974
2975 value = std::get<bool>(propertiesChanged.begin()->second);
2976 }
2977 catch (std::exception& e)
2978 {
2979 phosphor::logging::log<phosphor::logging::level::ERR>(
2980 "exception during reading dbus property : idButtonConfig");
2981 return;
2982 }
2983
2984 if (value)
2985 {
2986 idButtonIface->set_property("ButtonPressed", false);
2987 }
2988 else
2989 {
2990 idButtonIface->set_property("ButtonPressed", true);
2991 }
2992 };
2993
2994 sdbusplus::bus::match::match pulseEventMatcher(
2995 static_cast<sdbusplus::bus::bus&>(*conn),
2996 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2997 "PropertiesChanged',arg0='" +
2998 idButtonConfig.dbusName + "'",
2999 std::move(pulseEventMatcherCallback));
3000
3001 return pulseEventMatcher;
3002}
3003
3004inline static sdbusplus::bus::match::match postCompleteEventMonitor()
3005{
3006 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
3007 bool value = false;
3008 std::string thresholdInterface;
3009 std::string event;
3010 boost::container::flat_map<std::string, std::variant<bool>>
3011 propertiesChanged;
3012 try
3013 {
3014
3015 msg.read(thresholdInterface, propertiesChanged);
3016
3017 if (propertiesChanged.empty())
3018 {
3019 return;
3020 }
3021 event = propertiesChanged.begin()->first;
3022
3023 if (event.empty() | event != postCompleteConfig.lineName)
3024 {
3025 return;
3026 }
3027
3028 value = std::get<bool>(propertiesChanged.begin()->second);
3029 }
3030 catch (std::exception& e)
3031 {
3032 phosphor::logging::log<phosphor::logging::level::ERR>(
3033 "exception during reading dbus property : postCompleteConfig");
3034 return;
3035 }
3036
3037 if (value)
3038 {
3039 sendPowerControlEvent(Event::postCompleteDeAssert);
3040 osIface->set_property("OperatingSystemState",
3041 std::string("Inactive"));
3042 }
3043 else
3044 {
3045 sendPowerControlEvent(Event::postCompleteAssert);
3046 osIface->set_property("OperatingSystemState",
3047 std::string("Standby"));
3048 }
3049 };
3050
3051 sdbusplus::bus::match::match pulseEventMatcher(
3052 static_cast<sdbusplus::bus::bus&>(*conn),
3053 "type='signal',path='" + postCompleteConfig.path +
3054 "',interface='org.freedesktop.DBus.Properties',member='"
3055 "PropertiesChanged',arg0='" +
3056 postCompleteConfig.dbusName + "'",
3057 std::move(pulseEventMatcherCallback));
3058
3059 return pulseEventMatcher;
3060}
3061
3062int getProperty(ConfigData& configData)
3063{
3064 auto method = conn->new_method_call(
3065 configData.dbusName.c_str(), configData.path.c_str(),
3066 "org.freedesktop.DBus.Properties", "Get");
3067 method.append(configData.interface.c_str(), configData.lineName.c_str());
3068
3069 auto reply = conn->call(method);
3070 if (reply.is_method_error())
3071 {
3072 phosphor::logging::log<phosphor::logging::level::ERR>(
3073 "Error reading from Bus");
3074 return -1;
3075 }
3076 std::variant<int> resp;
3077 reply.read(resp);
3078 auto respValue = std::get_if<int>(&resp);
3079 if (!respValue)
3080 {
3081 phosphor::logging::log<phosphor::logging::level::ERR>(
3082 "Error reading response");
3083 return -1;
3084 }
3085 return (*respValue);
3086}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003087} // namespace power_control
3088
3089int main(int argc, char* argv[])
3090{
Lei YU92caa4c2021-02-23 16:59:25 +08003091 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05303092
3093 if (argc > 1)
3094 {
3095 node = argv[1];
3096 }
3097 std::string infoMsg =
3098 "Start Chassis power control service for host : " + node;
3099 phosphor::logging::log<phosphor::logging::level::INFO>(infoMsg.c_str());
3100
Lei YU92caa4c2021-02-23 16:59:25 +08003101 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003102
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303103 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08003104 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303105 {
Lei YU92caa4c2021-02-23 16:59:25 +08003106 std::string errMsg = "Host" + node + ": " + "Error in Parsing...";
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003107 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303108 }
3109
Priyatharshan P70120512020-09-16 18:47:20 +05303110 hostDbusName = "xyz.openbmc_project.State.Host" + node;
3111 chassisDbusName = "xyz.openbmc_project.State.Chassis" + node;
3112 osDbusName = "xyz.openbmc_project.State.OperatingSystem" + node;
3113 buttonDbusName = "xyz.openbmc_project.Chassis.Buttons" + node;
3114 nmiDbusName = "xyz.openbmc_project.Control.Host.NMI" + node;
3115 rstCauseDbusName = "xyz.openbmc_project.Control.Host.RestartCause" + node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003116
Priyatharshan P70120512020-09-16 18:47:20 +05303117 // Request all the dbus names
3118 conn->request_name(hostDbusName.c_str());
3119 conn->request_name(chassisDbusName.c_str());
3120 conn->request_name(osDbusName.c_str());
3121 conn->request_name(buttonDbusName.c_str());
3122 conn->request_name(nmiDbusName.c_str());
3123 conn->request_name(rstCauseDbusName.c_str());
3124
3125 if (sioPwrGoodConfig.lineName.empty() ||
3126 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05303127 {
Lei YU92caa4c2021-02-23 16:59:25 +08003128 sioEnabled = false;
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003129 phosphor::logging::log<phosphor::logging::level::INFO>(
3130 "SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05303131 }
3132
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003133 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303134 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003135 {
Priyatharshan P70120512020-09-16 18:47:20 +05303136 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
3137 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303138 {
3139 return -1;
3140 }
3141 }
Priyatharshan P70120512020-09-16 18:47:20 +05303142 else if (powerOkConfig.type == ConfigType::DBUS)
3143 {
3144
3145 static sdbusplus::bus::match::match powerOkEventMonitor =
3146 power_control::powerOkEventMonitor();
3147 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303148 else
3149 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003150 phosphor::logging::log<phosphor::logging::level::ERR>(
3151 "PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003152 return -1;
3153 }
3154
Lei YU92caa4c2021-02-23 16:59:25 +08003155 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003156 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05303157 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303158 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303159 {
Priyatharshan P70120512020-09-16 18:47:20 +05303160 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
3161 sioPowerGoodHandler, sioPowerGoodLine,
3162 sioPowerGoodEvent))
3163 {
3164 return -1;
3165 }
3166 }
3167 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
3168 {
3169 static sdbusplus::bus::match::match sioPwrGoodEventMonitor =
3170 power_control::sioPwrGoodEventMonitor();
3171 }
3172 else
3173 {
3174 phosphor::logging::log<phosphor::logging::level::ERR>(
3175 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303176 return -1;
3177 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003178
Priyatharshan P19c47a32020-08-12 18:16:43 +05303179 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303180 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303181 {
Priyatharshan P70120512020-09-16 18:47:20 +05303182 if (!requestGPIOEvents(sioOnControlConfig.lineName,
3183 sioOnControlHandler, sioOnControlLine,
3184 sioOnControlEvent))
3185 {
3186 return -1;
3187 }
3188 }
3189 else if (sioOnControlConfig.type == ConfigType::DBUS)
3190 {
3191 static sdbusplus::bus::match::match sioOnControlEventMonitor =
3192 power_control::sioOnControlEventMonitor();
3193 }
3194 else
3195 {
3196 phosphor::logging::log<phosphor::logging::level::ERR>(
3197 "sioOnControl name should be configured from json"
3198 "config file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303199 return -1;
3200 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003201
Priyatharshan P19c47a32020-08-12 18:16:43 +05303202 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303203 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303204 {
Priyatharshan P70120512020-09-16 18:47:20 +05303205 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
3206 sioS5Line, sioS5Event))
3207 {
3208 return -1;
3209 }
3210 }
3211 else if (sioS5Config.type == ConfigType::DBUS)
3212 {
3213 static sdbusplus::bus::match::match sioS5EventMonitor =
3214 power_control::sioS5EventMonitor();
3215 }
3216 else
3217 {
3218 phosphor::logging::log<phosphor::logging::level::ERR>(
3219 "sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303220 return -1;
3221 }
3222 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003223
3224 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303225 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003226 {
Priyatharshan P70120512020-09-16 18:47:20 +05303227 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
Lei YU92caa4c2021-02-23 16:59:25 +08003228 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303229 {
3230 return -1;
3231 }
3232 }
Priyatharshan P70120512020-09-16 18:47:20 +05303233 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303234 {
Priyatharshan P70120512020-09-16 18:47:20 +05303235 static sdbusplus::bus::match::match powerButtonEventMonitor =
3236 power_control::powerButtonEventMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003237 }
3238
3239 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303240 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003241 {
Priyatharshan P70120512020-09-16 18:47:20 +05303242 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
Lei YU92caa4c2021-02-23 16:59:25 +08003243 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303244 {
3245 return -1;
3246 }
3247 }
Priyatharshan P70120512020-09-16 18:47:20 +05303248 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303249 {
Priyatharshan P70120512020-09-16 18:47:20 +05303250 static sdbusplus::bus::match::match resetButtonEventMonitor =
3251 power_control::resetButtonEventMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003252 }
3253
3254 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303255 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303256 {
Priyatharshan P70120512020-09-16 18:47:20 +05303257 if (!nmiButtonConfig.lineName.empty())
3258 {
3259 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
3260 nmiButtonLine, nmiButtonEvent);
3261 }
3262 }
3263 else if (nmiButtonConfig.type == ConfigType::DBUS)
3264 {
3265 static sdbusplus::bus::match::match nmiButtonEventMonitor =
3266 power_control::nmiButtonEventMonitor();
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303267 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003268
3269 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303270 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303271 {
Priyatharshan P70120512020-09-16 18:47:20 +05303272 if (!idButtonConfig.lineName.empty())
3273 {
3274 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
3275 idButtonLine, idButtonEvent);
3276 }
3277 }
3278 else if (idButtonConfig.type == ConfigType::DBUS)
3279 {
3280 static sdbusplus::bus::match::match idButtonEventMonitor =
3281 power_control::idButtonEventMonitor();
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303282 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003283
Jason M. Billsfb957332021-01-28 13:18:46 -08003284#ifdef USE_PLT_RST
3285 sdbusplus::bus::match::match pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08003286 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08003287 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
3288 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08003289 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08003290#endif
3291
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003292 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303293 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003294 {
Priyatharshan P70120512020-09-16 18:47:20 +05303295 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
Lei YU92caa4c2021-02-23 16:59:25 +08003296 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303297 {
3298 return -1;
3299 }
3300 }
Priyatharshan P70120512020-09-16 18:47:20 +05303301 else if (postCompleteConfig.type == ConfigType::DBUS)
3302 {
3303 static sdbusplus::bus::match::match postCompleteEventMonitor =
3304 power_control::postCompleteEventMonitor();
3305 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303306 else
3307 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003308 phosphor::logging::log<phosphor::logging::level::ERR>(
3309 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003310 return -1;
3311 }
3312
3313 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05303314 if (!nmiOutConfig.lineName.empty())
3315 {
3316 setGPIOOutput(nmiOutConfig.lineName, 0, nmiOutLine);
3317 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003318
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003319 // Initialize POWER_OUT and RESET_OUT GPIO.
3320 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05303321 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003322 {
Priyatharshan P70120512020-09-16 18:47:20 +05303323 if (!setGPIOOutput(powerOutConfig.lineName, 1, line))
3324 {
3325 return -1;
3326 }
3327 }
3328 else
3329 {
3330 phosphor::logging::log<phosphor::logging::level::ERR>(
3331 "powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003332 return -1;
3333 }
3334
Priyatharshan P70120512020-09-16 18:47:20 +05303335 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003336 {
Priyatharshan P70120512020-09-16 18:47:20 +05303337 if (!setGPIOOutput(resetOutConfig.lineName, 1, line))
3338 {
3339 return -1;
3340 }
3341 }
3342 else
3343 {
3344 phosphor::logging::log<phosphor::logging::level::ERR>(
3345 "ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003346 return -1;
3347 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003348 // Release line
3349 line.reset();
3350
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003351 // Initialize the power state
Lei YU92caa4c2021-02-23 16:59:25 +08003352 powerState = PowerState::off;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003353 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05303354
3355 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003356 {
Priyatharshan P70120512020-09-16 18:47:20 +05303357 if (psPowerOKLine.get_value() > 0)
3358 {
3359 powerState = PowerState::on;
3360 }
3361 }
3362 else
3363 {
3364 if (getProperty(powerOkConfig))
3365 {
3366 powerState = PowerState::on;
3367 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003368 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003369 // Initialize the power state storage
Lei YU92caa4c2021-02-23 16:59:25 +08003370 if (initializePowerStateStorage() < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003371 {
3372 return -1;
3373 }
3374
3375 // Check if we need to start the Power Restore policy
Lei YU92caa4c2021-02-23 16:59:25 +08003376 powerRestorePolicyCheck();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003377
Lei YU92caa4c2021-02-23 16:59:25 +08003378 if (nmiOutLine)
3379 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003380
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003381 phosphor::logging::log<phosphor::logging::level::INFO>(
3382 "Initializing power state. ");
Lei YU92caa4c2021-02-23 16:59:25 +08003383 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003384
3385 // Power Control Service
3386 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003387 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003388
3389 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303390 hostIface =
3391 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
3392 "xyz.openbmc_project.State.Host");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003393
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003394 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08003395 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003396 "RequestedHostTransition",
3397 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
3398 [](const std::string& requested, std::string& resp) {
3399 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
3400 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003401 // if power button is masked, ignore this
3402 if (!powerButtonMask)
3403 {
3404 sendPowerControlEvent(Event::gracefulPowerOffRequest);
3405 addRestartCause(RestartCause::command);
3406 }
3407 else
3408 {
3409 phosphor::logging::log<phosphor::logging::level::INFO>(
3410 "Power Button Masked.");
3411 throw std::invalid_argument("Transition Request Masked");
3412 return 0;
3413 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003414 }
3415 else if (requested ==
3416 "xyz.openbmc_project.State.Host.Transition.On")
3417 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003418 // if power button is masked, ignore this
3419 if (!powerButtonMask)
3420 {
3421 sendPowerControlEvent(Event::powerOnRequest);
3422 addRestartCause(RestartCause::command);
3423 }
3424 else
3425 {
3426 phosphor::logging::log<phosphor::logging::level::INFO>(
3427 "Power Button Masked.");
3428 throw std::invalid_argument("Transition Request Masked");
3429 return 0;
3430 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003431 }
3432 else if (requested ==
3433 "xyz.openbmc_project.State.Host.Transition.Reboot")
3434 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003435 // if power button is masked, ignore this
3436 if (!powerButtonMask)
3437 {
3438 sendPowerControlEvent(Event::powerCycleRequest);
3439 addRestartCause(RestartCause::command);
3440 }
3441 else
3442 {
3443 phosphor::logging::log<phosphor::logging::level::INFO>(
3444 "Power Button Masked.");
3445 throw std::invalid_argument("Transition Request Masked");
3446 return 0;
3447 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003448 }
3449 else if (requested == "xyz.openbmc_project.State.Host.Transition."
3450 "GracefulWarmReboot")
3451 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003452 // if reset button is masked, ignore this
3453 if (!resetButtonMask)
3454 {
3455 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
3456 addRestartCause(RestartCause::command);
3457 }
3458 else
3459 {
3460 phosphor::logging::log<phosphor::logging::level::INFO>(
3461 "Reset Button Masked.");
3462 throw std::invalid_argument("Transition Request Masked");
3463 return 0;
3464 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003465 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003466 else if (requested == "xyz.openbmc_project.State.Host.Transition."
3467 "ForceWarmReboot")
3468 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003469 // if reset button is masked, ignore this
3470 if (!resetButtonMask)
3471 {
3472 sendPowerControlEvent(Event::resetRequest);
3473 addRestartCause(RestartCause::command);
3474 }
3475 else
3476 {
3477 phosphor::logging::log<phosphor::logging::level::INFO>(
3478 "Reset Button Masked.");
3479 throw std::invalid_argument("Transition Request Masked");
3480 return 0;
3481 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003482 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003483 else
3484 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003485 phosphor::logging::log<phosphor::logging::level::ERR>(
3486 "Unrecognized host state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003487 throw std::invalid_argument("Unrecognized Transition Request");
3488 return 0;
3489 }
3490 resp = requested;
3491 return 1;
3492 });
Lei YU92caa4c2021-02-23 16:59:25 +08003493 hostIface->register_property("CurrentHostState",
3494 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003495
Lei YU92caa4c2021-02-23 16:59:25 +08003496 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003497
3498 // Chassis Control Service
3499 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003500 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003501
3502 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003503 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05303504 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003505 "xyz.openbmc_project.State.Chassis");
3506
Lei YU92caa4c2021-02-23 16:59:25 +08003507 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003508 "RequestedPowerTransition",
3509 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
3510 [](const std::string& requested, std::string& resp) {
3511 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
3512 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003513 // if power button is masked, ignore this
3514 if (!powerButtonMask)
3515 {
3516 sendPowerControlEvent(Event::powerOffRequest);
3517 addRestartCause(RestartCause::command);
3518 }
3519 else
3520 {
3521 phosphor::logging::log<phosphor::logging::level::INFO>(
3522 "Power Button Masked.");
3523 throw std::invalid_argument("Transition Request Masked");
3524 return 0;
3525 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003526 }
3527 else if (requested ==
3528 "xyz.openbmc_project.State.Chassis.Transition.On")
3529 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003530 // if power button is masked, ignore this
3531 if (!powerButtonMask)
3532 {
3533 sendPowerControlEvent(Event::powerOnRequest);
3534 addRestartCause(RestartCause::command);
3535 }
3536 else
3537 {
3538 phosphor::logging::log<phosphor::logging::level::INFO>(
3539 "Power Button Masked.");
3540 throw std::invalid_argument("Transition Request Masked");
3541 return 0;
3542 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003543 }
3544 else if (requested ==
3545 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3546 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003547 // if power button is masked, ignore this
3548 if (!powerButtonMask)
3549 {
3550 sendPowerControlEvent(Event::powerCycleRequest);
3551 addRestartCause(RestartCause::command);
3552 }
3553 else
3554 {
3555 phosphor::logging::log<phosphor::logging::level::INFO>(
3556 "Power Button Masked.");
3557 throw std::invalid_argument("Transition Request Masked");
3558 return 0;
3559 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003560 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003561 else
3562 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003563 phosphor::logging::log<phosphor::logging::level::ERR>(
3564 "Unrecognized chassis state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003565 throw std::invalid_argument("Unrecognized Transition Request");
3566 return 0;
3567 }
3568 resp = requested;
3569 return 1;
3570 });
Lei YU92caa4c2021-02-23 16:59:25 +08003571 chassisIface->register_property("CurrentPowerState",
3572 std::string(getChassisState(powerState)));
3573 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003574
Lei YU92caa4c2021-02-23 16:59:25 +08003575 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003576
Vijay Khemka04175c22020-10-09 14:28:11 -07003577#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003578 // Chassis System Service
3579 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003580 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003581
3582 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003583 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003584 "/xyz/openbmc_project/state/chassis_system0",
3585 "xyz.openbmc_project.State.Chassis");
3586
Lei YU92caa4c2021-02-23 16:59:25 +08003587 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003588 "RequestedPowerTransition",
3589 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3590 [](const std::string& requested, std::string& resp) {
3591 if (requested ==
3592 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3593 {
Lei YU92caa4c2021-02-23 16:59:25 +08003594 systemReset();
3595 addRestartCause(RestartCause::command);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003596 }
3597 else
3598 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003599 phosphor::logging::log<phosphor::logging::level::ERR>(
3600 "Unrecognized chassis system state transition request.");
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003601 throw std::invalid_argument("Unrecognized Transition Request");
3602 return 0;
3603 }
3604 resp = requested;
3605 return 1;
3606 });
Lei YU92caa4c2021-02-23 16:59:25 +08003607 chassisSysIface->register_property(
3608 "CurrentPowerState", std::string(getChassisState(powerState)));
3609 chassisSysIface->register_property("LastStateChangeTime",
3610 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003611
Lei YU92caa4c2021-02-23 16:59:25 +08003612 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003613
Naveen Moses117c34e2021-05-26 20:10:51 +05303614 if (!slotPowerConfig.lineName.empty())
3615 {
3616 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3617 {
3618 return -1;
3619 }
3620
3621 slotPowerState = SlotPowerState::off;
3622 if (slotPowerLine.get_value() > 0)
3623 {
3624 slotPowerState = SlotPowerState::on;
3625 }
3626
3627 chassisSlotIface = chassisSysServer.add_interface(
3628 "/xyz/openbmc_project/state/chassis_system" + node,
3629 "xyz.openbmc_project.State.Chassis");
3630 chassisSlotIface->register_property(
3631 "RequestedPowerTransition",
3632 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3633 [](const std::string& requested, std::string& resp) {
3634 if (requested ==
3635 "xyz.openbmc_project.State.Chassis.Transition.On")
3636 {
3637 slotPowerOn();
3638 }
3639 else if (requested ==
3640 "xyz.openbmc_project.State.Chassis.Transition.Off")
3641 {
3642 slotPowerOff();
3643 }
3644 else if (requested == "xyz.openbmc_project.State.Chassis."
3645 "Transition.PowerCycle")
3646 {
3647 slotPowerCycle();
3648 }
3649 else
3650 {
3651 phosphor::logging::log<phosphor::logging::level::ERR>(
3652 "Unrecognized chassis system state transition "
3653 "request.\n");
3654 throw std::invalid_argument(
3655 "Unrecognized Transition Request");
3656 return 0;
3657 }
3658 resp = requested;
3659 return 1;
3660 });
3661 chassisSlotIface->register_property(
3662 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3663 chassisSlotIface->register_property("LastStateChangeTime",
3664 getCurrentTimeMs());
3665 chassisSlotIface->initialize();
3666 }
3667#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003668 // Buttons Service
3669 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003670 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003671
Priyatharshan P70120512020-09-16 18:47:20 +05303672 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003673 {
Priyatharshan P70120512020-09-16 18:47:20 +05303674 // Power Button Interface
3675 power_control::powerButtonIface = buttonsServer.add_interface(
3676 "/xyz/openbmc_project/chassis/buttons/power",
3677 "xyz.openbmc_project.Chassis.Buttons");
3678
3679 powerButtonIface->register_property(
3680 "ButtonMasked", false, [](const bool requested, bool& current) {
3681 if (requested)
3682 {
3683 if (powerButtonMask)
3684 {
3685 return 1;
3686 }
3687 if (!setGPIOOutput(powerOutConfig.lineName, 1,
3688 powerButtonMask))
3689 {
3690 throw std::runtime_error("Failed to request GPIO");
3691 return 0;
3692 }
3693 phosphor::logging::log<phosphor::logging::level::INFO>(
3694 "Power Button Masked.");
3695 }
3696 else
3697 {
3698 if (!powerButtonMask)
3699 {
3700 return 1;
3701 }
3702 phosphor::logging::log<phosphor::logging::level::INFO>(
3703 "Power Button Un-masked");
3704 powerButtonMask.reset();
3705 }
3706 // Update the mask setting
3707 current = requested;
3708 return 1;
3709 });
3710
3711 // Check power button state
3712 bool powerButtonPressed;
3713 if (powerButtonConfig.type == ConfigType::GPIO)
3714 {
3715 powerButtonPressed = powerButtonLine.get_value() == 0;
3716 }
3717 else
3718 {
3719 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3720 }
3721
3722 powerButtonIface->register_property("ButtonPressed",
3723 powerButtonPressed);
3724
3725 powerButtonIface->initialize();
3726 }
3727
3728 if (!resetButtonConfig.lineName.empty())
3729 {
3730 // Reset Button Interface
3731
Lei YU92caa4c2021-02-23 16:59:25 +08003732 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003733 "/xyz/openbmc_project/chassis/buttons/reset",
3734 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003735
Lei YU92caa4c2021-02-23 16:59:25 +08003736 resetButtonIface->register_property(
John Wang6c090072020-09-30 13:32:16 +08003737 "ButtonMasked", false, [](const bool requested, bool& current) {
3738 if (requested)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003739 {
Lei YU92caa4c2021-02-23 16:59:25 +08003740 if (resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003741 {
3742 return 1;
3743 }
Priyatharshan P70120512020-09-16 18:47:20 +05303744 if (!setGPIOOutput(resetOutConfig.lineName, 1,
3745 resetButtonMask))
John Wang6c090072020-09-30 13:32:16 +08003746 {
3747 throw std::runtime_error("Failed to request GPIO");
3748 return 0;
3749 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003750 phosphor::logging::log<phosphor::logging::level::INFO>(
3751 "Reset Button Masked.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003752 }
John Wang6c090072020-09-30 13:32:16 +08003753 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003754 {
Lei YU92caa4c2021-02-23 16:59:25 +08003755 if (!resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003756 {
3757 return 1;
3758 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003759 phosphor::logging::log<phosphor::logging::level::INFO>(
3760 "Reset Button Un-masked");
Lei YU92caa4c2021-02-23 16:59:25 +08003761 resetButtonMask.reset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003762 }
John Wang6c090072020-09-30 13:32:16 +08003763 // Update the mask setting
3764 current = requested;
3765 return 1;
3766 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003767
John Wang6c090072020-09-30 13:32:16 +08003768 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303769 bool resetButtonPressed;
3770 if (resetButtonConfig.type == ConfigType::GPIO)
3771 {
3772 resetButtonPressed = resetButtonLine.get_value() == 0;
3773 }
3774 else
3775 {
3776 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3777 }
3778
Lei YU92caa4c2021-02-23 16:59:25 +08003779 resetButtonIface->register_property("ButtonPressed",
3780 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003781
Lei YU92caa4c2021-02-23 16:59:25 +08003782 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003783 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003784
Lei YU92caa4c2021-02-23 16:59:25 +08003785 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003786 {
3787 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003788 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003789 "/xyz/openbmc_project/chassis/buttons/nmi",
3790 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003791
Lei YU92caa4c2021-02-23 16:59:25 +08003792 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003793 "ButtonMasked", false, [](const bool requested, bool& current) {
Lei YU92caa4c2021-02-23 16:59:25 +08003794 if (nmiButtonMasked == requested)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003795 {
3796 // NMI button mask is already set as requested, so no change
3797 return 1;
3798 }
3799 if (requested)
3800 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003801 phosphor::logging::log<phosphor::logging::level::INFO>(
3802 "NMI Button Masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003803 nmiButtonMasked = true;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003804 }
3805 else
3806 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003807 phosphor::logging::log<phosphor::logging::level::INFO>(
3808 "NMI Button Un-masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003809 nmiButtonMasked = false;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003810 }
3811 // Update the mask setting
Lei YU92caa4c2021-02-23 16:59:25 +08003812 current = nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003813 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003814 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003815
Vijay Khemka33a532d2019-11-14 16:50:35 -08003816 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303817 bool nmiButtonPressed;
3818 if (nmiButtonConfig.type == ConfigType::GPIO)
3819 {
3820 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3821 }
3822 else
3823 {
3824 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3825 }
3826
Lei YU92caa4c2021-02-23 16:59:25 +08003827 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003828
Lei YU92caa4c2021-02-23 16:59:25 +08003829 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003830 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003831
Lei YU92caa4c2021-02-23 16:59:25 +08003832 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003833 {
3834 // NMI out Service
3835 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003836 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003837
Vijay Khemka33a532d2019-11-14 16:50:35 -08003838 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303839 nmiOutIface = nmiOutServer.add_interface(
3840 "/xyz/openbmc_project/control/host" + node + "/nmi",
3841 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003842 nmiOutIface->register_method("NMI", nmiReset);
3843 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003844 }
Chen Yugang174ec662019-08-19 19:58:49 +08003845
Lei YU92caa4c2021-02-23 16:59:25 +08003846 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003847 {
3848 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003849 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003850 "/xyz/openbmc_project/chassis/buttons/id",
3851 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003852
Vijay Khemka33a532d2019-11-14 16:50:35 -08003853 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303854 bool idButtonPressed;
3855 if (idButtonConfig.type == ConfigType::GPIO)
3856 {
3857 idButtonPressed = idButtonLine.get_value() == 0;
3858 }
3859 else
3860 {
3861 idButtonPressed = getProperty(idButtonConfig) == 0;
3862 }
3863
Lei YU92caa4c2021-02-23 16:59:25 +08003864 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003865
Lei YU92caa4c2021-02-23 16:59:25 +08003866 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003867 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003868
3869 // OS State Service
3870 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003871 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003872
3873 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003874 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003875 "/xyz/openbmc_project/state/os",
3876 "xyz.openbmc_project.State.OperatingSystem.Status");
3877
3878 // Get the initial OS state based on POST complete
3879 // 0: Asserted, OS state is "Standby" (ready to boot)
3880 // 1: De-Asserted, OS state is "Inactive"
Priyatharshan P70120512020-09-16 18:47:20 +05303881 std::string osState;
3882 if (postCompleteConfig.type == ConfigType::GPIO)
3883 {
3884 osState = postCompleteLine.get_value() > 0 ? "Inactive" : "Standby";
3885 }
3886 else
3887 {
3888 osState = getProperty(postCompleteConfig) > 0 ? "Inactive" : "Standby";
3889 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003890
Lei YU92caa4c2021-02-23 16:59:25 +08003891 osIface->register_property("OperatingSystemState", std::string(osState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003892
Lei YU92caa4c2021-02-23 16:59:25 +08003893 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003894
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003895 // Restart Cause Service
3896 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003897 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003898
3899 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003900 restartCauseIface = restartCauseServer.add_interface(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003901 "/xyz/openbmc_project/control/host0/restart_cause",
3902 "xyz.openbmc_project.Control.Host.RestartCause");
3903
Lei YU92caa4c2021-02-23 16:59:25 +08003904 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003905 "RestartCause",
3906 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3907
Lei YU92caa4c2021-02-23 16:59:25 +08003908 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003909 "RequestedRestartCause",
3910 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3911 [](const std::string& requested, std::string& resp) {
3912 if (requested ==
3913 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3914 {
Lei YU92caa4c2021-02-23 16:59:25 +08003915 addRestartCause(RestartCause::watchdog);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003916 }
3917 else
3918 {
3919 throw std::invalid_argument(
3920 "Unrecognized RestartCause Request");
3921 return 0;
3922 }
3923
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003924 std::string logMsg = "RestartCause requested: " + requested;
3925 phosphor::logging::log<phosphor::logging::level::INFO>(
3926 logMsg.c_str());
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003927 resp = requested;
3928 return 1;
3929 });
3930
Lei YU92caa4c2021-02-23 16:59:25 +08003931 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003932
Lei YU92caa4c2021-02-23 16:59:25 +08003933 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003934
Lei YU92caa4c2021-02-23 16:59:25 +08003935 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003936
3937 return 0;
3938}