blob: d6d84338848416949e647df4ce8927a4cc0f2818 [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{
Naveen Mosesec972d82021-07-16 21:19:23 +0530266 std::string logMsg = "Host" + node + ": Moving to \"" +
267 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()),
Naveen Mosesec972d82021-07-16 21:19:23 +0530271 phosphor::logging::entry("HOST=%s", node.c_str()));
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 {
Zev Weiss6b8e3e02021-09-01 22:36:03 -0500759 std::string errMsg = "failed to create " +
760 powerControlDir.string() + ": " + ec.message();
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800761 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 }
Naveen Mosesec972d82021-07-16 21:19:23 +05303109 /* Currently for single host based systems additional busname is added
3110 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
3111 Going forward for single hosts the old bus name without zero numbering
3112 will be removed when all other applications adapted to the
3113 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
3114
3115 if (node == "0")
3116 {
3117 // 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 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303125
Zev Weissc4005bd2021-09-01 22:30:23 -05003126 hostDbusName += node;
3127 chassisDbusName += node;
3128 osDbusName += node;
3129 buttonDbusName += node;
3130 nmiDbusName += node;
3131 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003132
Priyatharshan P70120512020-09-16 18:47:20 +05303133 // Request all the dbus names
3134 conn->request_name(hostDbusName.c_str());
3135 conn->request_name(chassisDbusName.c_str());
3136 conn->request_name(osDbusName.c_str());
3137 conn->request_name(buttonDbusName.c_str());
3138 conn->request_name(nmiDbusName.c_str());
3139 conn->request_name(rstCauseDbusName.c_str());
3140
3141 if (sioPwrGoodConfig.lineName.empty() ||
3142 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05303143 {
Lei YU92caa4c2021-02-23 16:59:25 +08003144 sioEnabled = false;
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003145 phosphor::logging::log<phosphor::logging::level::INFO>(
3146 "SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05303147 }
3148
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003149 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303150 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003151 {
Priyatharshan P70120512020-09-16 18:47:20 +05303152 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
3153 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303154 {
3155 return -1;
3156 }
3157 }
Priyatharshan P70120512020-09-16 18:47:20 +05303158 else if (powerOkConfig.type == ConfigType::DBUS)
3159 {
3160
3161 static sdbusplus::bus::match::match powerOkEventMonitor =
3162 power_control::powerOkEventMonitor();
3163 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303164 else
3165 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003166 phosphor::logging::log<phosphor::logging::level::ERR>(
3167 "PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003168 return -1;
3169 }
3170
Lei YU92caa4c2021-02-23 16:59:25 +08003171 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003172 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05303173 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303174 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303175 {
Priyatharshan P70120512020-09-16 18:47:20 +05303176 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
3177 sioPowerGoodHandler, sioPowerGoodLine,
3178 sioPowerGoodEvent))
3179 {
3180 return -1;
3181 }
3182 }
3183 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
3184 {
3185 static sdbusplus::bus::match::match sioPwrGoodEventMonitor =
3186 power_control::sioPwrGoodEventMonitor();
3187 }
3188 else
3189 {
3190 phosphor::logging::log<phosphor::logging::level::ERR>(
3191 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303192 return -1;
3193 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003194
Priyatharshan P19c47a32020-08-12 18:16:43 +05303195 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303196 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303197 {
Priyatharshan P70120512020-09-16 18:47:20 +05303198 if (!requestGPIOEvents(sioOnControlConfig.lineName,
3199 sioOnControlHandler, sioOnControlLine,
3200 sioOnControlEvent))
3201 {
3202 return -1;
3203 }
3204 }
3205 else if (sioOnControlConfig.type == ConfigType::DBUS)
3206 {
3207 static sdbusplus::bus::match::match sioOnControlEventMonitor =
3208 power_control::sioOnControlEventMonitor();
3209 }
3210 else
3211 {
3212 phosphor::logging::log<phosphor::logging::level::ERR>(
3213 "sioOnControl name should be configured from json"
3214 "config file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303215 return -1;
3216 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003217
Priyatharshan P19c47a32020-08-12 18:16:43 +05303218 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303219 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303220 {
Priyatharshan P70120512020-09-16 18:47:20 +05303221 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
3222 sioS5Line, sioS5Event))
3223 {
3224 return -1;
3225 }
3226 }
3227 else if (sioS5Config.type == ConfigType::DBUS)
3228 {
3229 static sdbusplus::bus::match::match sioS5EventMonitor =
3230 power_control::sioS5EventMonitor();
3231 }
3232 else
3233 {
3234 phosphor::logging::log<phosphor::logging::level::ERR>(
3235 "sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303236 return -1;
3237 }
3238 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003239
3240 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303241 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003242 {
Priyatharshan P70120512020-09-16 18:47:20 +05303243 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
Lei YU92caa4c2021-02-23 16:59:25 +08003244 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303245 {
3246 return -1;
3247 }
3248 }
Priyatharshan P70120512020-09-16 18:47:20 +05303249 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303250 {
Priyatharshan P70120512020-09-16 18:47:20 +05303251 static sdbusplus::bus::match::match powerButtonEventMonitor =
3252 power_control::powerButtonEventMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003253 }
3254
3255 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303256 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003257 {
Priyatharshan P70120512020-09-16 18:47:20 +05303258 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
Lei YU92caa4c2021-02-23 16:59:25 +08003259 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303260 {
3261 return -1;
3262 }
3263 }
Priyatharshan P70120512020-09-16 18:47:20 +05303264 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303265 {
Priyatharshan P70120512020-09-16 18:47:20 +05303266 static sdbusplus::bus::match::match resetButtonEventMonitor =
3267 power_control::resetButtonEventMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003268 }
3269
3270 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303271 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303272 {
Priyatharshan P70120512020-09-16 18:47:20 +05303273 if (!nmiButtonConfig.lineName.empty())
3274 {
3275 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
3276 nmiButtonLine, nmiButtonEvent);
3277 }
3278 }
3279 else if (nmiButtonConfig.type == ConfigType::DBUS)
3280 {
3281 static sdbusplus::bus::match::match nmiButtonEventMonitor =
3282 power_control::nmiButtonEventMonitor();
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303283 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003284
3285 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303286 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303287 {
Priyatharshan P70120512020-09-16 18:47:20 +05303288 if (!idButtonConfig.lineName.empty())
3289 {
3290 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
3291 idButtonLine, idButtonEvent);
3292 }
3293 }
3294 else if (idButtonConfig.type == ConfigType::DBUS)
3295 {
3296 static sdbusplus::bus::match::match idButtonEventMonitor =
3297 power_control::idButtonEventMonitor();
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303298 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003299
Jason M. Billsfb957332021-01-28 13:18:46 -08003300#ifdef USE_PLT_RST
3301 sdbusplus::bus::match::match pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08003302 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08003303 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
3304 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08003305 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08003306#endif
3307
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003308 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303309 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003310 {
Priyatharshan P70120512020-09-16 18:47:20 +05303311 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
Lei YU92caa4c2021-02-23 16:59:25 +08003312 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303313 {
3314 return -1;
3315 }
3316 }
Priyatharshan P70120512020-09-16 18:47:20 +05303317 else if (postCompleteConfig.type == ConfigType::DBUS)
3318 {
3319 static sdbusplus::bus::match::match postCompleteEventMonitor =
3320 power_control::postCompleteEventMonitor();
3321 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303322 else
3323 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003324 phosphor::logging::log<phosphor::logging::level::ERR>(
3325 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003326 return -1;
3327 }
3328
3329 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05303330 if (!nmiOutConfig.lineName.empty())
3331 {
3332 setGPIOOutput(nmiOutConfig.lineName, 0, nmiOutLine);
3333 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003334
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003335 // Initialize POWER_OUT and RESET_OUT GPIO.
3336 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05303337 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003338 {
Priyatharshan P70120512020-09-16 18:47:20 +05303339 if (!setGPIOOutput(powerOutConfig.lineName, 1, line))
3340 {
3341 return -1;
3342 }
3343 }
3344 else
3345 {
3346 phosphor::logging::log<phosphor::logging::level::ERR>(
3347 "powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003348 return -1;
3349 }
3350
Priyatharshan P70120512020-09-16 18:47:20 +05303351 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003352 {
Priyatharshan P70120512020-09-16 18:47:20 +05303353 if (!setGPIOOutput(resetOutConfig.lineName, 1, line))
3354 {
3355 return -1;
3356 }
3357 }
3358 else
3359 {
3360 phosphor::logging::log<phosphor::logging::level::ERR>(
3361 "ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003362 return -1;
3363 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003364 // Release line
3365 line.reset();
3366
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003367 // Initialize the power state
Lei YU92caa4c2021-02-23 16:59:25 +08003368 powerState = PowerState::off;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003369 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05303370
3371 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003372 {
Priyatharshan P70120512020-09-16 18:47:20 +05303373 if (psPowerOKLine.get_value() > 0)
3374 {
3375 powerState = PowerState::on;
3376 }
3377 }
3378 else
3379 {
3380 if (getProperty(powerOkConfig))
3381 {
3382 powerState = PowerState::on;
3383 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003384 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003385 // Initialize the power state storage
Lei YU92caa4c2021-02-23 16:59:25 +08003386 if (initializePowerStateStorage() < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003387 {
3388 return -1;
3389 }
3390
3391 // Check if we need to start the Power Restore policy
Lei YU92caa4c2021-02-23 16:59:25 +08003392 powerRestorePolicyCheck();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003393
Lei YU92caa4c2021-02-23 16:59:25 +08003394 if (nmiOutLine)
3395 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003396
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003397 phosphor::logging::log<phosphor::logging::level::INFO>(
3398 "Initializing power state. ");
Lei YU92caa4c2021-02-23 16:59:25 +08003399 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003400
3401 // Power Control Service
3402 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003403 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003404
3405 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303406 hostIface =
3407 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
3408 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003409 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08003410 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003411 "RequestedHostTransition",
3412 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
3413 [](const std::string& requested, std::string& resp) {
3414 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
3415 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003416 // if power button is masked, ignore this
3417 if (!powerButtonMask)
3418 {
3419 sendPowerControlEvent(Event::gracefulPowerOffRequest);
3420 addRestartCause(RestartCause::command);
3421 }
3422 else
3423 {
3424 phosphor::logging::log<phosphor::logging::level::INFO>(
3425 "Power Button Masked.");
3426 throw std::invalid_argument("Transition Request Masked");
3427 return 0;
3428 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003429 }
3430 else if (requested ==
3431 "xyz.openbmc_project.State.Host.Transition.On")
3432 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003433 // if power button is masked, ignore this
3434 if (!powerButtonMask)
3435 {
3436 sendPowerControlEvent(Event::powerOnRequest);
3437 addRestartCause(RestartCause::command);
3438 }
3439 else
3440 {
3441 phosphor::logging::log<phosphor::logging::level::INFO>(
3442 "Power Button Masked.");
3443 throw std::invalid_argument("Transition Request Masked");
3444 return 0;
3445 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003446 }
3447 else if (requested ==
3448 "xyz.openbmc_project.State.Host.Transition.Reboot")
3449 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003450 // if power button is masked, ignore this
3451 if (!powerButtonMask)
3452 {
3453 sendPowerControlEvent(Event::powerCycleRequest);
3454 addRestartCause(RestartCause::command);
3455 }
3456 else
3457 {
3458 phosphor::logging::log<phosphor::logging::level::INFO>(
3459 "Power Button Masked.");
3460 throw std::invalid_argument("Transition Request Masked");
3461 return 0;
3462 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003463 }
3464 else if (requested == "xyz.openbmc_project.State.Host.Transition."
3465 "GracefulWarmReboot")
3466 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003467 // if reset button is masked, ignore this
3468 if (!resetButtonMask)
3469 {
3470 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
3471 addRestartCause(RestartCause::command);
3472 }
3473 else
3474 {
3475 phosphor::logging::log<phosphor::logging::level::INFO>(
3476 "Reset Button Masked.");
3477 throw std::invalid_argument("Transition Request Masked");
3478 return 0;
3479 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003480 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003481 else if (requested == "xyz.openbmc_project.State.Host.Transition."
3482 "ForceWarmReboot")
3483 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003484 // if reset button is masked, ignore this
3485 if (!resetButtonMask)
3486 {
3487 sendPowerControlEvent(Event::resetRequest);
3488 addRestartCause(RestartCause::command);
3489 }
3490 else
3491 {
3492 phosphor::logging::log<phosphor::logging::level::INFO>(
3493 "Reset Button Masked.");
3494 throw std::invalid_argument("Transition Request Masked");
3495 return 0;
3496 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003497 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003498 else
3499 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003500 phosphor::logging::log<phosphor::logging::level::ERR>(
3501 "Unrecognized host state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003502 throw std::invalid_argument("Unrecognized Transition Request");
3503 return 0;
3504 }
3505 resp = requested;
3506 return 1;
3507 });
Lei YU92caa4c2021-02-23 16:59:25 +08003508 hostIface->register_property("CurrentHostState",
3509 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003510
Lei YU92caa4c2021-02-23 16:59:25 +08003511 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003512
3513 // Chassis Control Service
3514 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003515 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003516
3517 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003518 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05303519 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003520 "xyz.openbmc_project.State.Chassis");
3521
Lei YU92caa4c2021-02-23 16:59:25 +08003522 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003523 "RequestedPowerTransition",
3524 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
3525 [](const std::string& requested, std::string& resp) {
3526 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
3527 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003528 // if power button is masked, ignore this
3529 if (!powerButtonMask)
3530 {
3531 sendPowerControlEvent(Event::powerOffRequest);
3532 addRestartCause(RestartCause::command);
3533 }
3534 else
3535 {
3536 phosphor::logging::log<phosphor::logging::level::INFO>(
3537 "Power Button Masked.");
3538 throw std::invalid_argument("Transition Request Masked");
3539 return 0;
3540 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003541 }
3542 else if (requested ==
3543 "xyz.openbmc_project.State.Chassis.Transition.On")
3544 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003545 // if power button is masked, ignore this
3546 if (!powerButtonMask)
3547 {
3548 sendPowerControlEvent(Event::powerOnRequest);
3549 addRestartCause(RestartCause::command);
3550 }
3551 else
3552 {
3553 phosphor::logging::log<phosphor::logging::level::INFO>(
3554 "Power Button Masked.");
3555 throw std::invalid_argument("Transition Request Masked");
3556 return 0;
3557 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003558 }
3559 else if (requested ==
3560 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3561 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003562 // if power button is masked, ignore this
3563 if (!powerButtonMask)
3564 {
3565 sendPowerControlEvent(Event::powerCycleRequest);
3566 addRestartCause(RestartCause::command);
3567 }
3568 else
3569 {
3570 phosphor::logging::log<phosphor::logging::level::INFO>(
3571 "Power Button Masked.");
3572 throw std::invalid_argument("Transition Request Masked");
3573 return 0;
3574 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003575 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003576 else
3577 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003578 phosphor::logging::log<phosphor::logging::level::ERR>(
3579 "Unrecognized chassis state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003580 throw std::invalid_argument("Unrecognized Transition Request");
3581 return 0;
3582 }
3583 resp = requested;
3584 return 1;
3585 });
Lei YU92caa4c2021-02-23 16:59:25 +08003586 chassisIface->register_property("CurrentPowerState",
3587 std::string(getChassisState(powerState)));
3588 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003589
Lei YU92caa4c2021-02-23 16:59:25 +08003590 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003591
Vijay Khemka04175c22020-10-09 14:28:11 -07003592#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003593 // Chassis System Service
3594 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003595 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003596
3597 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003598 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003599 "/xyz/openbmc_project/state/chassis_system0",
3600 "xyz.openbmc_project.State.Chassis");
3601
Lei YU92caa4c2021-02-23 16:59:25 +08003602 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003603 "RequestedPowerTransition",
3604 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3605 [](const std::string& requested, std::string& resp) {
3606 if (requested ==
3607 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3608 {
Lei YU92caa4c2021-02-23 16:59:25 +08003609 systemReset();
3610 addRestartCause(RestartCause::command);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003611 }
3612 else
3613 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003614 phosphor::logging::log<phosphor::logging::level::ERR>(
3615 "Unrecognized chassis system state transition request.");
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003616 throw std::invalid_argument("Unrecognized Transition Request");
3617 return 0;
3618 }
3619 resp = requested;
3620 return 1;
3621 });
Lei YU92caa4c2021-02-23 16:59:25 +08003622 chassisSysIface->register_property(
3623 "CurrentPowerState", std::string(getChassisState(powerState)));
3624 chassisSysIface->register_property("LastStateChangeTime",
3625 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003626
Lei YU92caa4c2021-02-23 16:59:25 +08003627 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003628
Naveen Moses117c34e2021-05-26 20:10:51 +05303629 if (!slotPowerConfig.lineName.empty())
3630 {
3631 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3632 {
3633 return -1;
3634 }
3635
3636 slotPowerState = SlotPowerState::off;
3637 if (slotPowerLine.get_value() > 0)
3638 {
3639 slotPowerState = SlotPowerState::on;
3640 }
3641
3642 chassisSlotIface = chassisSysServer.add_interface(
3643 "/xyz/openbmc_project/state/chassis_system" + node,
3644 "xyz.openbmc_project.State.Chassis");
3645 chassisSlotIface->register_property(
3646 "RequestedPowerTransition",
3647 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3648 [](const std::string& requested, std::string& resp) {
3649 if (requested ==
3650 "xyz.openbmc_project.State.Chassis.Transition.On")
3651 {
3652 slotPowerOn();
3653 }
3654 else if (requested ==
3655 "xyz.openbmc_project.State.Chassis.Transition.Off")
3656 {
3657 slotPowerOff();
3658 }
3659 else if (requested == "xyz.openbmc_project.State.Chassis."
3660 "Transition.PowerCycle")
3661 {
3662 slotPowerCycle();
3663 }
3664 else
3665 {
3666 phosphor::logging::log<phosphor::logging::level::ERR>(
3667 "Unrecognized chassis system state transition "
3668 "request.\n");
3669 throw std::invalid_argument(
3670 "Unrecognized Transition Request");
3671 return 0;
3672 }
3673 resp = requested;
3674 return 1;
3675 });
3676 chassisSlotIface->register_property(
3677 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3678 chassisSlotIface->register_property("LastStateChangeTime",
3679 getCurrentTimeMs());
3680 chassisSlotIface->initialize();
3681 }
3682#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003683 // Buttons Service
3684 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003685 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003686
Priyatharshan P70120512020-09-16 18:47:20 +05303687 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003688 {
Priyatharshan P70120512020-09-16 18:47:20 +05303689 // Power Button Interface
3690 power_control::powerButtonIface = buttonsServer.add_interface(
3691 "/xyz/openbmc_project/chassis/buttons/power",
3692 "xyz.openbmc_project.Chassis.Buttons");
3693
3694 powerButtonIface->register_property(
3695 "ButtonMasked", false, [](const bool requested, bool& current) {
3696 if (requested)
3697 {
3698 if (powerButtonMask)
3699 {
3700 return 1;
3701 }
3702 if (!setGPIOOutput(powerOutConfig.lineName, 1,
3703 powerButtonMask))
3704 {
3705 throw std::runtime_error("Failed to request GPIO");
3706 return 0;
3707 }
3708 phosphor::logging::log<phosphor::logging::level::INFO>(
3709 "Power Button Masked.");
3710 }
3711 else
3712 {
3713 if (!powerButtonMask)
3714 {
3715 return 1;
3716 }
3717 phosphor::logging::log<phosphor::logging::level::INFO>(
3718 "Power Button Un-masked");
3719 powerButtonMask.reset();
3720 }
3721 // Update the mask setting
3722 current = requested;
3723 return 1;
3724 });
3725
3726 // Check power button state
3727 bool powerButtonPressed;
3728 if (powerButtonConfig.type == ConfigType::GPIO)
3729 {
3730 powerButtonPressed = powerButtonLine.get_value() == 0;
3731 }
3732 else
3733 {
3734 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3735 }
3736
3737 powerButtonIface->register_property("ButtonPressed",
3738 powerButtonPressed);
3739
3740 powerButtonIface->initialize();
3741 }
3742
3743 if (!resetButtonConfig.lineName.empty())
3744 {
3745 // Reset Button Interface
3746
Lei YU92caa4c2021-02-23 16:59:25 +08003747 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003748 "/xyz/openbmc_project/chassis/buttons/reset",
3749 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003750
Lei YU92caa4c2021-02-23 16:59:25 +08003751 resetButtonIface->register_property(
John Wang6c090072020-09-30 13:32:16 +08003752 "ButtonMasked", false, [](const bool requested, bool& current) {
3753 if (requested)
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 }
Priyatharshan P70120512020-09-16 18:47:20 +05303759 if (!setGPIOOutput(resetOutConfig.lineName, 1,
3760 resetButtonMask))
John Wang6c090072020-09-30 13:32:16 +08003761 {
3762 throw std::runtime_error("Failed to request GPIO");
3763 return 0;
3764 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003765 phosphor::logging::log<phosphor::logging::level::INFO>(
3766 "Reset Button Masked.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003767 }
John Wang6c090072020-09-30 13:32:16 +08003768 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003769 {
Lei YU92caa4c2021-02-23 16:59:25 +08003770 if (!resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003771 {
3772 return 1;
3773 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003774 phosphor::logging::log<phosphor::logging::level::INFO>(
3775 "Reset Button Un-masked");
Lei YU92caa4c2021-02-23 16:59:25 +08003776 resetButtonMask.reset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003777 }
John Wang6c090072020-09-30 13:32:16 +08003778 // Update the mask setting
3779 current = requested;
3780 return 1;
3781 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003782
John Wang6c090072020-09-30 13:32:16 +08003783 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303784 bool resetButtonPressed;
3785 if (resetButtonConfig.type == ConfigType::GPIO)
3786 {
3787 resetButtonPressed = resetButtonLine.get_value() == 0;
3788 }
3789 else
3790 {
3791 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3792 }
3793
Lei YU92caa4c2021-02-23 16:59:25 +08003794 resetButtonIface->register_property("ButtonPressed",
3795 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003796
Lei YU92caa4c2021-02-23 16:59:25 +08003797 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003798 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003799
Lei YU92caa4c2021-02-23 16:59:25 +08003800 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003801 {
3802 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003803 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003804 "/xyz/openbmc_project/chassis/buttons/nmi",
3805 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003806
Lei YU92caa4c2021-02-23 16:59:25 +08003807 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003808 "ButtonMasked", false, [](const bool requested, bool& current) {
Lei YU92caa4c2021-02-23 16:59:25 +08003809 if (nmiButtonMasked == requested)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003810 {
3811 // NMI button mask is already set as requested, so no change
3812 return 1;
3813 }
3814 if (requested)
3815 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003816 phosphor::logging::log<phosphor::logging::level::INFO>(
3817 "NMI Button Masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003818 nmiButtonMasked = true;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003819 }
3820 else
3821 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003822 phosphor::logging::log<phosphor::logging::level::INFO>(
3823 "NMI Button Un-masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003824 nmiButtonMasked = false;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003825 }
3826 // Update the mask setting
Lei YU92caa4c2021-02-23 16:59:25 +08003827 current = nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003828 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003829 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003830
Vijay Khemka33a532d2019-11-14 16:50:35 -08003831 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303832 bool nmiButtonPressed;
3833 if (nmiButtonConfig.type == ConfigType::GPIO)
3834 {
3835 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3836 }
3837 else
3838 {
3839 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3840 }
3841
Lei YU92caa4c2021-02-23 16:59:25 +08003842 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003843
Lei YU92caa4c2021-02-23 16:59:25 +08003844 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003845 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003846
Lei YU92caa4c2021-02-23 16:59:25 +08003847 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003848 {
3849 // NMI out Service
3850 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003851 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003852
Vijay Khemka33a532d2019-11-14 16:50:35 -08003853 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303854 nmiOutIface = nmiOutServer.add_interface(
3855 "/xyz/openbmc_project/control/host" + node + "/nmi",
3856 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003857 nmiOutIface->register_method("NMI", nmiReset);
3858 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003859 }
Chen Yugang174ec662019-08-19 19:58:49 +08003860
Lei YU92caa4c2021-02-23 16:59:25 +08003861 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003862 {
3863 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003864 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003865 "/xyz/openbmc_project/chassis/buttons/id",
3866 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003867
Vijay Khemka33a532d2019-11-14 16:50:35 -08003868 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303869 bool idButtonPressed;
3870 if (idButtonConfig.type == ConfigType::GPIO)
3871 {
3872 idButtonPressed = idButtonLine.get_value() == 0;
3873 }
3874 else
3875 {
3876 idButtonPressed = getProperty(idButtonConfig) == 0;
3877 }
3878
Lei YU92caa4c2021-02-23 16:59:25 +08003879 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003880
Lei YU92caa4c2021-02-23 16:59:25 +08003881 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003882 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003883
3884 // OS State Service
3885 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003886 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003887
3888 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003889 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003890 "/xyz/openbmc_project/state/os",
3891 "xyz.openbmc_project.State.OperatingSystem.Status");
3892
3893 // Get the initial OS state based on POST complete
3894 // 0: Asserted, OS state is "Standby" (ready to boot)
3895 // 1: De-Asserted, OS state is "Inactive"
Priyatharshan P70120512020-09-16 18:47:20 +05303896 std::string osState;
3897 if (postCompleteConfig.type == ConfigType::GPIO)
3898 {
3899 osState = postCompleteLine.get_value() > 0 ? "Inactive" : "Standby";
3900 }
3901 else
3902 {
3903 osState = getProperty(postCompleteConfig) > 0 ? "Inactive" : "Standby";
3904 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003905
Lei YU92caa4c2021-02-23 16:59:25 +08003906 osIface->register_property("OperatingSystemState", std::string(osState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003907
Lei YU92caa4c2021-02-23 16:59:25 +08003908 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003909
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003910 // Restart Cause Service
3911 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003912 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003913
3914 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003915 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303916 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003917 "xyz.openbmc_project.Control.Host.RestartCause");
3918
Lei YU92caa4c2021-02-23 16:59:25 +08003919 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003920 "RestartCause",
3921 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3922
Lei YU92caa4c2021-02-23 16:59:25 +08003923 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003924 "RequestedRestartCause",
3925 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3926 [](const std::string& requested, std::string& resp) {
3927 if (requested ==
3928 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3929 {
Lei YU92caa4c2021-02-23 16:59:25 +08003930 addRestartCause(RestartCause::watchdog);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003931 }
3932 else
3933 {
3934 throw std::invalid_argument(
3935 "Unrecognized RestartCause Request");
3936 return 0;
3937 }
3938
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003939 std::string logMsg = "RestartCause requested: " + requested;
3940 phosphor::logging::log<phosphor::logging::level::INFO>(
3941 logMsg.c_str());
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003942 resp = requested;
3943 return 1;
3944 });
3945
Lei YU92caa4c2021-02-23 16:59:25 +08003946 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003947
Lei YU92caa4c2021-02-23 16:59:25 +08003948 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003949
Lei YU92caa4c2021-02-23 16:59:25 +08003950 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003951
3952 return 0;
3953}