blob: b25734988fb4e0da4b2ba97c39720e5dd26d2080 [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;
Jean-Marie Verdun50937e72021-08-31 09:15:49 -070068 bool polarity;
Priyatharshan P70120512020-09-16 18:47:20 +053069 ConfigType type;
70};
71
72static ConfigData powerOutConfig;
73static ConfigData powerOkConfig;
74static ConfigData resetOutConfig;
75static ConfigData nmiOutConfig;
76static ConfigData sioPwrGoodConfig;
77static ConfigData sioOnControlConfig;
78static ConfigData sioS5Config;
79static ConfigData postCompleteConfig;
80static ConfigData powerButtonConfig;
81static ConfigData resetButtonConfig;
82static ConfigData idButtonConfig;
83static ConfigData nmiButtonConfig;
Naveen Moses117c34e2021-05-26 20:10:51 +053084static ConfigData slotPowerConfig;
85
Priyatharshan P70120512020-09-16 18:47:20 +053086// map for storing list of gpio parameters whose config are to be read from x86
87// power control json config
88boost::container::flat_map<std::string, ConfigData*> powerSignalMap = {
89 {"PowerOut", &powerOutConfig},
90 {"PowerOk", &powerOkConfig},
91 {"ResetOut", &resetOutConfig},
92 {"NMIOut", &nmiOutConfig},
93 {"SioPowerGood", &sioPwrGoodConfig},
94 {"SioOnControl", &sioOnControlConfig},
95 {"SIOS5", &sioS5Config},
96 {"PostComplete", &postCompleteConfig},
97 {"PowerButton", &powerButtonConfig},
98 {"ResetButton", &resetButtonConfig},
99 {"IdButton", &idButtonConfig},
Naveen Moses117c34e2021-05-26 20:10:51 +0530100 {"NMIButton", &nmiButtonConfig},
101 {"SlotPower", &slotPowerConfig}};
Priyatharshan P70120512020-09-16 18:47:20 +0530102
103static std::string hostDbusName = "xyz.openbmc_project.State.Host";
104static std::string chassisDbusName = "xyz.openbmc_project.State.Chassis";
105static std::string osDbusName = "xyz.openbmc_project.State.OperatingSystem";
106static std::string buttonDbusName = "xyz.openbmc_project.Chassis.Buttons";
107static std::string nmiDbusName = "xyz.openbmc_project.Control.Host.NMI";
108static std::string rstCauseDbusName =
109 "xyz.openbmc_project.Control.Host.RestartCause";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700110static std::shared_ptr<sdbusplus::asio::dbus_interface> hostIface;
111static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700112#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -0700113static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSysIface;
Naveen Moses117c34e2021-05-26 20:10:51 +0530114static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSlotIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700115#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700116static std::shared_ptr<sdbusplus::asio::dbus_interface> powerButtonIface;
117static std::shared_ptr<sdbusplus::asio::dbus_interface> resetButtonIface;
118static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiButtonIface;
119static std::shared_ptr<sdbusplus::asio::dbus_interface> osIface;
120static std::shared_ptr<sdbusplus::asio::dbus_interface> idButtonIface;
Chen Yugang174ec662019-08-19 19:58:49 +0800121static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiOutIface;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700122static std::shared_ptr<sdbusplus::asio::dbus_interface> restartCauseIface;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700123
124static gpiod::line powerButtonMask;
125static gpiod::line resetButtonMask;
126static bool nmiButtonMasked = false;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700127
Priyatharshan P70120512020-09-16 18:47:20 +0530128// This map contains all timer values that are to be read from json config
129boost::container::flat_map<std::string, int> TimerMap = {
130 {"powerPulseTimeMs", 200},
131 {"forceOffPulseTimeMs", 15000},
132 {"resetPulseTimeMs", 500},
133 {"powerCycleTimeMs", 5000},
134 {"sioPowerGoodWatchdogTimeMs", 1000},
135 {"psPowerOKWatchdogTimeMs", 8000},
136 {"gracefulPowerOffTimeS", (5 * 60)},
137 {"warmResetCheckTimeMs", 500},
Naveen Moses117c34e2021-05-26 20:10:51 +0530138 {"powerOffSaveTimeMs", 7000},
139 {"slotPowerCycleTimeMs", 200}};
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700140const static std::filesystem::path powerControlDir = "/var/lib/power-control";
141const static constexpr std::string_view powerStateFile = "power-state";
142
143static bool nmiEnabled = true;
Priyatharshan P19c47a32020-08-12 18:16:43 +0530144static bool sioEnabled = true;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700145
146// Timers
147// Time holding GPIOs asserted
148static boost::asio::steady_timer gpioAssertTimer(io);
149// Time between off and on during a power cycle
150static boost::asio::steady_timer powerCycleTimer(io);
151// Time OS gracefully powering off
152static boost::asio::steady_timer gracefulPowerOffTimer(io);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700153// Time the warm reset check
154static boost::asio::steady_timer warmResetCheckTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700155// Time power supply power OK assertion on power-on
156static boost::asio::steady_timer psPowerOKWatchdogTimer(io);
157// Time SIO power good assertion on power-on
158static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io);
159// Time power-off state save for power loss tracking
160static boost::asio::steady_timer powerStateSaveTimer(io);
161// POH timer
162static boost::asio::steady_timer pohCounterTimer(io);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700163// Time when to allow restart cause updates
164static boost::asio::steady_timer restartCauseTimer(io);
Naveen Moses117c34e2021-05-26 20:10:51 +0530165static boost::asio::steady_timer slotPowerCycleTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700166
167// GPIO Lines and Event Descriptors
168static gpiod::line psPowerOKLine;
169static boost::asio::posix::stream_descriptor psPowerOKEvent(io);
170static gpiod::line sioPowerGoodLine;
171static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io);
172static gpiod::line sioOnControlLine;
173static boost::asio::posix::stream_descriptor sioOnControlEvent(io);
174static gpiod::line sioS5Line;
175static boost::asio::posix::stream_descriptor sioS5Event(io);
176static gpiod::line powerButtonLine;
177static boost::asio::posix::stream_descriptor powerButtonEvent(io);
178static gpiod::line resetButtonLine;
179static boost::asio::posix::stream_descriptor resetButtonEvent(io);
180static gpiod::line nmiButtonLine;
181static boost::asio::posix::stream_descriptor nmiButtonEvent(io);
182static gpiod::line idButtonLine;
183static boost::asio::posix::stream_descriptor idButtonEvent(io);
184static gpiod::line postCompleteLine;
185static boost::asio::posix::stream_descriptor postCompleteEvent(io);
186static gpiod::line nmiOutLine;
Naveen Moses117c34e2021-05-26 20:10:51 +0530187static gpiod::line slotPowerLine;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700188
189static constexpr uint8_t beepPowerFail = 8;
190
191static void beep(const uint8_t& beepPriority)
192{
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800193 std::string logMsg = "Beep with priority: " + std::to_string(beepPriority);
194 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700195
196 conn->async_method_call(
197 [](boost::system::error_code ec) {
198 if (ec)
199 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800200 std::string errMsg =
201 "beep returned error with async_method_call (ec = " +
202 ec.message();
203 phosphor::logging::log<phosphor::logging::level::ERR>(
204 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700205 return;
206 }
207 },
208 "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
209 "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
210}
211
212enum class PowerState
213{
214 on,
215 waitForPSPowerOK,
216 waitForSIOPowerGood,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700217 off,
218 transitionToOff,
219 gracefulTransitionToOff,
220 cycleOff,
221 transitionToCycleOff,
222 gracefulTransitionToCycleOff,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700223 checkForWarmReset,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700224};
225static PowerState powerState;
226static std::string getPowerStateName(PowerState state)
227{
228 switch (state)
229 {
230 case PowerState::on:
231 return "On";
232 break;
233 case PowerState::waitForPSPowerOK:
234 return "Wait for Power Supply Power OK";
235 break;
236 case PowerState::waitForSIOPowerGood:
237 return "Wait for SIO Power Good";
238 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700239 case PowerState::off:
240 return "Off";
241 break;
242 case PowerState::transitionToOff:
243 return "Transition to Off";
244 break;
245 case PowerState::gracefulTransitionToOff:
246 return "Graceful Transition to Off";
247 break;
248 case PowerState::cycleOff:
249 return "Power Cycle Off";
250 break;
251 case PowerState::transitionToCycleOff:
252 return "Transition to Power Cycle Off";
253 break;
254 case PowerState::gracefulTransitionToCycleOff:
255 return "Graceful Transition to Power Cycle Off";
256 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700257 case PowerState::checkForWarmReset:
258 return "Check for Warm Reset";
259 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700260 default:
261 return "unknown state: " + std::to_string(static_cast<int>(state));
262 break;
263 }
264}
265static void logStateTransition(const PowerState state)
266{
Naveen Mosesec972d82021-07-16 21:19:23 +0530267 std::string logMsg = "Host" + node + ": Moving to \"" +
268 getPowerStateName(state) + "\" state";
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700269 phosphor::logging::log<phosphor::logging::level::INFO>(
270 logMsg.c_str(),
Vijay Khemkad6c5ad12020-05-27 14:57:52 -0700271 phosphor::logging::entry("STATE=%s", getPowerStateName(state).c_str()),
Naveen Mosesec972d82021-07-16 21:19:23 +0530272 phosphor::logging::entry("HOST=%s", node.c_str()));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700273}
274
275enum class Event
276{
277 psPowerOKAssert,
278 psPowerOKDeAssert,
279 sioPowerGoodAssert,
280 sioPowerGoodDeAssert,
281 sioS5Assert,
282 sioS5DeAssert,
Jason M. Billsfb957332021-01-28 13:18:46 -0800283 pltRstAssert,
284 pltRstDeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700285 postCompleteAssert,
286 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700287 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700288 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700289 powerCycleTimerExpired,
290 psPowerOKWatchdogTimerExpired,
291 sioPowerGoodWatchdogTimerExpired,
292 gracefulPowerOffTimerExpired,
293 powerOnRequest,
294 powerOffRequest,
295 powerCycleRequest,
296 resetRequest,
297 gracefulPowerOffRequest,
298 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700299 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700300};
301static std::string getEventName(Event event)
302{
303 switch (event)
304 {
305 case Event::psPowerOKAssert:
306 return "power supply power OK assert";
307 break;
308 case Event::psPowerOKDeAssert:
309 return "power supply power OK de-assert";
310 break;
311 case Event::sioPowerGoodAssert:
312 return "SIO power good assert";
313 break;
314 case Event::sioPowerGoodDeAssert:
315 return "SIO power good de-assert";
316 break;
317 case Event::sioS5Assert:
318 return "SIO S5 assert";
319 break;
320 case Event::sioS5DeAssert:
321 return "SIO S5 de-assert";
322 break;
Jason M. Billsfb957332021-01-28 13:18:46 -0800323 case Event::pltRstAssert:
324 return "PLT_RST assert";
325 break;
326 case Event::pltRstDeAssert:
327 return "PLT_RST de-assert";
328 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700329 case Event::postCompleteAssert:
330 return "POST Complete assert";
331 break;
332 case Event::postCompleteDeAssert:
333 return "POST Complete de-assert";
334 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700335 case Event::powerButtonPressed:
336 return "power button pressed";
337 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700338 case Event::resetButtonPressed:
339 return "reset button pressed";
340 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700341 case Event::powerCycleTimerExpired:
342 return "power cycle timer expired";
343 break;
344 case Event::psPowerOKWatchdogTimerExpired:
345 return "power supply power OK watchdog timer expired";
346 break;
347 case Event::sioPowerGoodWatchdogTimerExpired:
348 return "SIO power good watchdog timer expired";
349 break;
350 case Event::gracefulPowerOffTimerExpired:
351 return "graceful power-off timer expired";
352 break;
353 case Event::powerOnRequest:
354 return "power-on request";
355 break;
356 case Event::powerOffRequest:
357 return "power-off request";
358 break;
359 case Event::powerCycleRequest:
360 return "power-cycle request";
361 break;
362 case Event::resetRequest:
363 return "reset request";
364 break;
365 case Event::gracefulPowerOffRequest:
366 return "graceful power-off request";
367 break;
368 case Event::gracefulPowerCycleRequest:
369 return "graceful power-cycle request";
370 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700371 case Event::warmResetDetected:
372 return "warm reset detected";
373 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700374 default:
375 return "unknown event: " + std::to_string(static_cast<int>(event));
376 break;
377 }
378}
379static void logEvent(const std::string_view stateHandler, const Event event)
380{
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700381 std::string logMsg{stateHandler};
382 logMsg += ": " + getEventName(event) + " event received";
383 phosphor::logging::log<phosphor::logging::level::INFO>(
384 logMsg.c_str(),
385 phosphor::logging::entry("EVENT=%s", getEventName(event).c_str()));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700386}
387
388// Power state handlers
389static void powerStateOn(const Event event);
390static void powerStateWaitForPSPowerOK(const Event event);
391static void powerStateWaitForSIOPowerGood(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700392static void powerStateOff(const Event event);
393static void powerStateTransitionToOff(const Event event);
394static void powerStateGracefulTransitionToOff(const Event event);
395static void powerStateCycleOff(const Event event);
396static void powerStateTransitionToCycleOff(const Event event);
397static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700398static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700399
400static std::function<void(const Event)> getPowerStateHandler(PowerState state)
401{
402 switch (state)
403 {
404 case PowerState::on:
405 return powerStateOn;
406 break;
407 case PowerState::waitForPSPowerOK:
408 return powerStateWaitForPSPowerOK;
409 break;
410 case PowerState::waitForSIOPowerGood:
411 return powerStateWaitForSIOPowerGood;
412 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700413 case PowerState::off:
414 return powerStateOff;
415 break;
416 case PowerState::transitionToOff:
417 return powerStateTransitionToOff;
418 break;
419 case PowerState::gracefulTransitionToOff:
420 return powerStateGracefulTransitionToOff;
421 break;
422 case PowerState::cycleOff:
423 return powerStateCycleOff;
424 break;
425 case PowerState::transitionToCycleOff:
426 return powerStateTransitionToCycleOff;
427 break;
428 case PowerState::gracefulTransitionToCycleOff:
429 return powerStateGracefulTransitionToCycleOff;
430 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700431 case PowerState::checkForWarmReset:
432 return powerStateCheckForWarmReset;
433 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700434 default:
Zev Weiss047bcb52020-08-20 21:28:11 +0000435 return nullptr;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700436 break;
437 }
438};
439
440static void sendPowerControlEvent(const Event event)
441{
442 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
443 if (handler == nullptr)
444 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800445 std::string errMsg = "Failed to find handler for power state: " +
446 std::to_string(static_cast<int>(powerState));
447 phosphor::logging::log<phosphor::logging::level::INFO>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700448 return;
449 }
450 handler(event);
451}
452
453static uint64_t getCurrentTimeMs()
454{
455 struct timespec time = {};
456
457 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
458 {
459 return 0;
460 }
461 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
462 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
463
464 return currentTimeMs;
465}
466
467static constexpr std::string_view getHostState(const PowerState state)
468{
469 switch (state)
470 {
471 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700472 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700473 case PowerState::gracefulTransitionToCycleOff:
474 return "xyz.openbmc_project.State.Host.HostState.Running";
475 break;
476 case PowerState::waitForPSPowerOK:
477 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700478 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700479 case PowerState::transitionToOff:
480 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700481 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700482 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700483 return "xyz.openbmc_project.State.Host.HostState.Off";
484 break;
485 default:
486 return "";
487 break;
488 }
489};
490static constexpr std::string_view getChassisState(const PowerState state)
491{
492 switch (state)
493 {
494 case PowerState::on:
495 case PowerState::transitionToOff:
496 case PowerState::gracefulTransitionToOff:
497 case PowerState::transitionToCycleOff:
498 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700499 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700500 return "xyz.openbmc_project.State.Chassis.PowerState.On";
501 break;
502 case PowerState::waitForPSPowerOK:
503 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700504 case PowerState::off:
505 case PowerState::cycleOff:
506 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
507 break;
508 default:
509 return "";
510 break;
511 }
512};
Naveen Moses117c34e2021-05-26 20:10:51 +0530513#ifdef CHASSIS_SYSTEM_RESET
514enum class SlotPowerState
515{
516 on,
517 off,
518};
519static SlotPowerState slotPowerState;
520static constexpr std::string_view getSlotState(const SlotPowerState state)
521{
522 switch (state)
523 {
524 case SlotPowerState::on:
525 return "xyz.openbmc_project.State.Chassis.PowerState.On";
526 break;
527 case SlotPowerState::off:
528 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
529 break;
530 default:
531 return "";
532 break;
533 }
534};
535static void setSlotPowerState(const SlotPowerState state)
536{
537 slotPowerState = state;
538 chassisSlotIface->set_property("CurrentPowerState",
539 std::string(getSlotState(slotPowerState)));
540 chassisSlotIface->set_property("LastStateChangeTime", getCurrentTimeMs());
541}
542#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700543static void savePowerState(const PowerState state)
544{
545 powerStateSaveTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +0530546 std::chrono::milliseconds(TimerMap["powerOffSaveTimeMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700547 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
548 if (ec)
549 {
550 // operation_aborted is expected if timer is canceled before
551 // completion.
552 if (ec != boost::asio::error::operation_aborted)
553 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800554 std::string errMsg =
555 "Power-state save async_wait failed: " + ec.message();
556 phosphor::logging::log<phosphor::logging::level::ERR>(
557 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700558 }
559 return;
560 }
561 std::ofstream powerStateStream(powerControlDir / powerStateFile);
562 powerStateStream << getChassisState(state);
563 });
564}
565static void setPowerState(const PowerState state)
566{
567 powerState = state;
568 logStateTransition(state);
569
570 hostIface->set_property("CurrentHostState",
571 std::string(getHostState(powerState)));
572
573 chassisIface->set_property("CurrentPowerState",
574 std::string(getChassisState(powerState)));
575 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
576
577 // Save the power state for the restore policy
578 savePowerState(state);
579}
580
581enum class RestartCause
582{
583 command,
584 resetButton,
585 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700586 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700587 powerPolicyOn,
588 powerPolicyRestore,
589 softReset,
590};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700591static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700592static std::string getRestartCause(RestartCause cause)
593{
594 switch (cause)
595 {
596 case RestartCause::command:
597 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
598 break;
599 case RestartCause::resetButton:
600 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
601 break;
602 case RestartCause::powerButton:
603 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
604 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700605 case RestartCause::watchdog:
606 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
607 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700608 case RestartCause::powerPolicyOn:
609 return "xyz.openbmc_project.State.Host.RestartCause."
610 "PowerPolicyAlwaysOn";
611 break;
612 case RestartCause::powerPolicyRestore:
613 return "xyz.openbmc_project.State.Host.RestartCause."
614 "PowerPolicyPreviousState";
615 break;
616 case RestartCause::softReset:
617 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
618 break;
619 default:
620 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
621 break;
622 }
623}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700624static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700625{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700626 // Add this to the set of causes for this restart
627 causeSet.insert(cause);
628}
629static void clearRestartCause()
630{
631 // Clear the set for the next restart
632 causeSet.clear();
633}
634static void setRestartCauseProperty(const std::string& cause)
635{
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800636 std::string logMsg = "RestartCause set to " + cause;
637 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700638 restartCauseIface->set_property("RestartCause", cause);
639}
Rashmi RV89f61312020-01-22 15:41:50 +0530640
641static void resetACBootProperty()
642{
643 if ((causeSet.contains(RestartCause::command)) ||
644 (causeSet.contains(RestartCause::softReset)))
645 {
646 conn->async_method_call(
647 [](boost::system::error_code ec) {
648 if (ec)
649 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800650 phosphor::logging::log<phosphor::logging::level::ERR>(
651 "failed to reset ACBoot property");
Rashmi RV89f61312020-01-22 15:41:50 +0530652 }
653 },
654 "xyz.openbmc_project.Settings",
655 "/xyz/openbmc_project/control/host0/ac_boot",
656 "org.freedesktop.DBus.Properties", "Set",
657 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
658 std::variant<std::string>{"False"});
659 }
660}
661
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700662static void setRestartCause()
663{
664 // Determine the actual restart cause based on the set of causes
665 std::string restartCause =
666 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
667 if (causeSet.contains(RestartCause::watchdog))
668 {
669 restartCause = getRestartCause(RestartCause::watchdog);
670 }
671 else if (causeSet.contains(RestartCause::command))
672 {
673 restartCause = getRestartCause(RestartCause::command);
674 }
675 else if (causeSet.contains(RestartCause::resetButton))
676 {
677 restartCause = getRestartCause(RestartCause::resetButton);
678 }
679 else if (causeSet.contains(RestartCause::powerButton))
680 {
681 restartCause = getRestartCause(RestartCause::powerButton);
682 }
683 else if (causeSet.contains(RestartCause::powerPolicyOn))
684 {
685 restartCause = getRestartCause(RestartCause::powerPolicyOn);
686 }
687 else if (causeSet.contains(RestartCause::powerPolicyRestore))
688 {
689 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
690 }
691 else if (causeSet.contains(RestartCause::softReset))
692 {
693 restartCause = getRestartCause(RestartCause::softReset);
694 }
695
696 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700697}
698
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700699static void systemPowerGoodFailedLog()
700{
701 sd_journal_send(
702 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
703 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
704 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Priyatharshan P70120512020-09-16 18:47:20 +0530705 TimerMap["sioPowerGoodWatchdogTimeMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700706}
707
708static void psPowerOKFailedLog()
709{
710 sd_journal_send(
711 "MESSAGE=PowerControl: power supply power good failed to assert",
712 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
713 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Priyatharshan P70120512020-09-16 18:47:20 +0530714 TimerMap["psPowerOKWatchdogTimeMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700715}
716
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700717static void powerRestorePolicyLog()
718{
719 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
720 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
721 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
722}
723
724static void powerButtonPressLog()
725{
726 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
727 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
728 "OpenBMC.0.1.PowerButtonPressed", NULL);
729}
730
731static void resetButtonPressLog()
732{
733 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
734 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
735 "OpenBMC.0.1.ResetButtonPressed", NULL);
736}
737
738static void nmiButtonPressLog()
739{
740 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
741 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
742 "OpenBMC.0.1.NMIButtonPressed", NULL);
743}
744
745static void nmiDiagIntLog()
746{
747 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
748 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
749 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
750}
751
752static int initializePowerStateStorage()
753{
754 // create the power control directory if it doesn't exist
755 std::error_code ec;
756 if (!(std::filesystem::create_directories(powerControlDir, ec)))
757 {
758 if (ec.value() != 0)
759 {
Zev Weiss6b8e3e02021-09-01 22:36:03 -0500760 std::string errMsg = "failed to create " +
761 powerControlDir.string() + ": " + ec.message();
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800762 phosphor::logging::log<phosphor::logging::level::ERR>(
763 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700764 return -1;
765 }
766 }
767 // Create the power state file if it doesn't exist
768 if (!std::filesystem::exists(powerControlDir / powerStateFile))
769 {
770 std::ofstream powerStateStream(powerControlDir / powerStateFile);
771 powerStateStream << getChassisState(powerState);
772 }
773 return 0;
774}
775
776static bool wasPowerDropped()
777{
778 std::ifstream powerStateStream(powerControlDir / powerStateFile);
779 if (!powerStateStream.is_open())
780 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800781 phosphor::logging::log<phosphor::logging::level::ERR>(
782 "Failed to open power state file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700783 return false;
784 }
785
786 std::string state;
787 std::getline(powerStateStream, state);
788 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
789}
790
791static void invokePowerRestorePolicy(const std::string& policy)
792{
793 // Async events may call this twice, but we only want to run once
794 static bool policyInvoked = false;
795 if (policyInvoked)
796 {
797 return;
798 }
799 policyInvoked = true;
800
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800801 std::string logMsg = "Power restore delay expired, invoking " + policy;
802 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700803 if (policy ==
804 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
805 {
806 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700807 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700808 }
809 else if (policy == "xyz.openbmc_project.Control.Power.RestorePolicy."
810 "Policy.Restore")
811 {
812 if (wasPowerDropped())
813 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800814 phosphor::logging::log<phosphor::logging::level::INFO>(
815 "Power was dropped, restoring Host On state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700816 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700817 setRestartCauseProperty(
818 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700819 }
820 else
821 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800822 phosphor::logging::log<phosphor::logging::level::INFO>(
823 "No power drop, restoring Host Off state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700824 }
825 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -0700826 // We're done with the previous power state for the restore policy, so store
827 // the current state
828 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700829}
830
831static void powerRestorePolicyDelay(int delay)
832{
833 // Async events may call this twice, but we only want to run once
834 static bool delayStarted = false;
835 if (delayStarted)
836 {
837 return;
838 }
839 delayStarted = true;
840 // Calculate the delay from now to meet the requested delay
841 // Subtract the approximate uboot time
842 static constexpr const int ubootSeconds = 20;
843 delay -= ubootSeconds;
844 // Subtract the time since boot
845 struct sysinfo info = {};
846 if (sysinfo(&info) == 0)
847 {
848 delay -= info.uptime;
849 }
850 // 0 is the minimum delay
851 delay = std::max(delay, 0);
852
853 static boost::asio::steady_timer powerRestorePolicyTimer(io);
854 powerRestorePolicyTimer.expires_after(std::chrono::seconds(delay));
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800855 std::string logMsg =
856 "Power restore delay of " + std::to_string(delay) + " seconds started";
857 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700858 powerRestorePolicyTimer.async_wait([](const boost::system::error_code ec) {
859 if (ec)
860 {
861 // operation_aborted is expected if timer is canceled before
862 // completion.
863 if (ec != boost::asio::error::operation_aborted)
864 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800865 std::string errMsg =
866 "power restore policy async_wait failed: " + ec.message();
867 phosphor::logging::log<phosphor::logging::level::ERR>(
868 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700869 }
870 return;
871 }
872 // Get Power Restore Policy
873 // In case PowerRestorePolicy is not available, set a match for it
874 static std::unique_ptr<sdbusplus::bus::match::match>
875 powerRestorePolicyMatch = std::make_unique<
876 sdbusplus::bus::match::match>(
877 *conn,
878 "type='signal',interface='org.freedesktop.DBus.Properties',"
879 "member='PropertiesChanged',arg0namespace='xyz.openbmc_"
880 "project.Control.Power.RestorePolicy'",
881 [](sdbusplus::message::message& msg) {
882 std::string interfaceName;
883 boost::container::flat_map<std::string,
884 std::variant<std::string>>
885 propertiesChanged;
886 std::string policy;
887 try
888 {
889 msg.read(interfaceName, propertiesChanged);
890 policy = std::get<std::string>(
891 propertiesChanged.begin()->second);
892 }
893 catch (std::exception& e)
894 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800895 phosphor::logging::log<phosphor::logging::level::ERR>(
896 "Unable to read power restore policy value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700897 powerRestorePolicyMatch.reset();
898 return;
899 }
900 invokePowerRestorePolicy(policy);
901 powerRestorePolicyMatch.reset();
902 });
903
904 // Check if it's already on DBus
905 conn->async_method_call(
906 [](boost::system::error_code ec,
907 const std::variant<std::string>& policyProperty) {
908 if (ec)
909 {
910 return;
911 }
912 powerRestorePolicyMatch.reset();
913 const std::string* policy =
914 std::get_if<std::string>(&policyProperty);
915 if (policy == nullptr)
916 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800917 phosphor::logging::log<phosphor::logging::level::ERR>(
918 "Unable to read power restore policy value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700919 return;
920 }
921 invokePowerRestorePolicy(*policy);
922 },
923 "xyz.openbmc_project.Settings",
924 "/xyz/openbmc_project/control/host0/power_restore_policy",
925 "org.freedesktop.DBus.Properties", "Get",
926 "xyz.openbmc_project.Control.Power.RestorePolicy",
927 "PowerRestorePolicy");
928 });
929}
930
931static void powerRestorePolicyStart()
932{
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800933 phosphor::logging::log<phosphor::logging::level::INFO>(
934 "Power restore policy started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700935 powerRestorePolicyLog();
936
937 // Get the desired delay time
938 // In case PowerRestoreDelay is not available, set a match for it
939 static std::unique_ptr<sdbusplus::bus::match::match>
940 powerRestoreDelayMatch = std::make_unique<sdbusplus::bus::match::match>(
941 *conn,
942 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
943 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Control."
944 "Power.RestoreDelay'",
945 [](sdbusplus::message::message& msg) {
946 std::string interfaceName;
947 boost::container::flat_map<std::string, std::variant<uint16_t>>
948 propertiesChanged;
949 int delay = 0;
950 try
951 {
952 msg.read(interfaceName, propertiesChanged);
953 delay =
954 std::get<uint16_t>(propertiesChanged.begin()->second);
955 }
956 catch (std::exception& e)
957 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800958 phosphor::logging::log<phosphor::logging::level::ERR>(
959 "Unable to read power restore delay value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700960 powerRestoreDelayMatch.reset();
961 return;
962 }
963 powerRestorePolicyDelay(delay);
964 powerRestoreDelayMatch.reset();
965 });
966
967 // Check if it's already on DBus
968 conn->async_method_call(
969 [](boost::system::error_code ec,
970 const std::variant<uint16_t>& delayProperty) {
971 if (ec)
972 {
973 return;
974 }
975 powerRestoreDelayMatch.reset();
976 const uint16_t* delay = std::get_if<uint16_t>(&delayProperty);
977 if (delay == nullptr)
978 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800979 phosphor::logging::log<phosphor::logging::level::ERR>(
980 "Unable to read power restore delay value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700981 return;
982 }
983 powerRestorePolicyDelay(*delay);
984 },
985 "xyz.openbmc_project.Settings",
986 "/xyz/openbmc_project/control/power_restore_delay",
987 "org.freedesktop.DBus.Properties", "Get",
988 "xyz.openbmc_project.Control.Power.RestoreDelay", "PowerRestoreDelay");
989}
990
991static void powerRestorePolicyCheck()
992{
993 // In case ACBoot is not available, set a match for it
994 static std::unique_ptr<sdbusplus::bus::match::match> acBootMatch =
995 std::make_unique<sdbusplus::bus::match::match>(
996 *conn,
997 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
998 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Common."
999 "ACBoot'",
1000 [](sdbusplus::message::message& msg) {
1001 std::string interfaceName;
1002 boost::container::flat_map<std::string,
1003 std::variant<std::string>>
1004 propertiesChanged;
1005 std::string acBoot;
1006 try
1007 {
1008 msg.read(interfaceName, propertiesChanged);
1009 acBoot = std::get<std::string>(
1010 propertiesChanged.begin()->second);
1011 }
1012 catch (std::exception& e)
1013 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001014 phosphor::logging::log<phosphor::logging::level::ERR>(
1015 "Unable to read AC Boot status");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001016 acBootMatch.reset();
1017 return;
1018 }
1019 if (acBoot == "Unknown")
1020 {
1021 return;
1022 }
1023 if (acBoot == "True")
1024 {
1025 // Start the Power Restore policy
1026 powerRestorePolicyStart();
1027 }
1028 acBootMatch.reset();
1029 });
1030
1031 // Check if it's already on DBus
1032 conn->async_method_call(
1033 [](boost::system::error_code ec,
1034 const std::variant<std::string>& acBootProperty) {
1035 if (ec)
1036 {
1037 return;
1038 }
1039 const std::string* acBoot =
1040 std::get_if<std::string>(&acBootProperty);
1041 if (acBoot == nullptr)
1042 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001043 phosphor::logging::log<phosphor::logging::level::ERR>(
1044 "Unable to read AC Boot status");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001045 return;
1046 }
1047 if (*acBoot == "Unknown")
1048 {
1049 return;
1050 }
1051 if (*acBoot == "True")
1052 {
1053 // Start the Power Restore policy
1054 powerRestorePolicyStart();
1055 }
1056 acBootMatch.reset();
1057 },
1058 "xyz.openbmc_project.Settings",
1059 "/xyz/openbmc_project/control/host0/ac_boot",
1060 "org.freedesktop.DBus.Properties", "Get",
1061 "xyz.openbmc_project.Common.ACBoot", "ACBoot");
1062}
1063
1064static bool requestGPIOEvents(
1065 const std::string& name, const std::function<void()>& handler,
1066 gpiod::line& gpioLine,
1067 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
1068{
1069 // Find the GPIO line
1070 gpioLine = gpiod::find_line(name);
1071 if (!gpioLine)
1072 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001073 std::string errMsg = "Failed to find the " + name + " line";
1074 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001075 return false;
1076 }
1077
1078 try
1079 {
1080 gpioLine.request(
1081 {"power-control", gpiod::line_request::EVENT_BOTH_EDGES});
1082 }
1083 catch (std::exception&)
1084 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001085 std::string errMsg = "Failed to request events for " + name;
1086 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001087 return false;
1088 }
1089
1090 int gpioLineFd = gpioLine.event_get_fd();
1091 if (gpioLineFd < 0)
1092 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001093 std::string errMsg = "Failed to name " + name + " fd";
1094 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001095 return false;
1096 }
1097
1098 gpioEventDescriptor.assign(gpioLineFd);
1099
1100 gpioEventDescriptor.async_wait(
1101 boost::asio::posix::stream_descriptor::wait_read,
1102 [&name, handler](const boost::system::error_code ec) {
1103 if (ec)
1104 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001105 std::string errMsg =
1106 name + " fd handler error: " + ec.message();
1107 phosphor::logging::log<phosphor::logging::level::ERR>(
1108 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001109 // TODO: throw here to force power-control to restart?
1110 return;
1111 }
1112 handler();
1113 });
1114 return true;
1115}
1116
1117static bool setGPIOOutput(const std::string& name, const int value,
1118 gpiod::line& gpioLine)
1119{
1120 // Find the GPIO line
1121 gpioLine = gpiod::find_line(name);
1122 if (!gpioLine)
1123 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001124 std::string errMsg = "Failed to find the " + name + " line";
1125 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001126 return false;
1127 }
1128
1129 // Request GPIO output to specified value
1130 try
1131 {
1132 gpioLine.request({__FUNCTION__, gpiod::line_request::DIRECTION_OUTPUT},
1133 value);
1134 }
1135 catch (std::exception&)
1136 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001137 std::string errMsg = "Failed to request " + name + " output";
1138 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001139 return false;
1140 }
1141
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001142 std::string logMsg = name + " set to " + std::to_string(value);
1143 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001144 return true;
1145}
1146
1147static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1148 const std::string& name, const int value,
1149 const int durationMs)
1150{
1151 // Set the masked GPIO line to the specified value
1152 maskedGPIOLine.set_value(value);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001153 std::string logMsg = name + " set to " + std::to_string(value);
1154 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001155 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001156 gpioAssertTimer.async_wait([maskedGPIOLine, value,
1157 name](const boost::system::error_code ec) {
1158 // Set the masked GPIO line back to the opposite value
1159 maskedGPIOLine.set_value(!value);
1160 std::string logMsg = name + " released";
1161 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
1162 if (ec)
1163 {
1164 // operation_aborted is expected if timer is canceled before
1165 // completion.
1166 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001167 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001168 std::string errMsg =
1169 name + " async_wait failed: " + ec.message();
1170 phosphor::logging::log<phosphor::logging::level::ERR>(
1171 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001172 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001173 }
1174 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001175 return 0;
1176}
1177
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001178static int setGPIOOutputForMs(const ConfigData& config, const int value,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001179 const int durationMs)
1180{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001181 int polarizedvalue;
1182 if (!config.polarity)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001183 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001184 polarizedvalue = value;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001185 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001186 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001187 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001188 polarizedvalue = !value;
1189 }
1190 // If the requested GPIO is masked, use the mask line to set the output
1191 if (powerButtonMask && config.lineName == powerOutConfig.lineName)
1192 {
1193 return setMaskedGPIOOutputForMs(powerButtonMask, config.lineName,
1194 polarizedvalue, durationMs);
1195 }
1196 if (resetButtonMask && config.lineName == resetOutConfig.lineName)
1197 {
1198 return setMaskedGPIOOutputForMs(resetButtonMask, config.lineName,
1199 polarizedvalue, durationMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001200 }
1201
1202 // No mask set, so request and set the GPIO normally
1203 gpiod::line gpioLine;
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001204 if (!setGPIOOutput(config.lineName, polarizedvalue, gpioLine))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001205 {
1206 return -1;
1207 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001208 const std::string name = config.lineName;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001209 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001210 gpioAssertTimer.async_wait([gpioLine, value,
1211 name](const boost::system::error_code ec) {
1212 // Set the GPIO line back to the opposite value
1213 gpioLine.set_value(!value);
1214 std::string logMsg = name + " released";
1215 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
1216 if (ec)
1217 {
1218 // operation_aborted is expected if timer is canceled before
1219 // completion.
1220 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001221 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001222 std::string errMsg =
1223 name + " async_wait failed: " + ec.message();
1224 phosphor::logging::log<phosphor::logging::level::ERR>(
1225 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001226 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001227 }
1228 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001229 return 0;
1230}
1231
1232static void powerOn()
1233{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001234 setGPIOOutputForMs(powerOutConfig, 0, TimerMap["powerPulseTimeMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001235}
Naveen Moses117c34e2021-05-26 20:10:51 +05301236#ifdef CHASSIS_SYSTEM_RESET
1237static int slotPowerOn()
1238{
1239 if (power_control::slotPowerState != power_control::SlotPowerState::on)
1240 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001241
Naveen Moses117c34e2021-05-26 20:10:51 +05301242 slotPowerLine.set_value(1);
1243
1244 if (slotPowerLine.get_value() > 0)
1245 {
1246 setSlotPowerState(SlotPowerState::on);
1247 phosphor::logging::log<phosphor::logging::level::INFO>(
1248 "Slot Power is switched On\n");
1249 }
1250 else
1251 {
1252 return -1;
1253 }
1254 }
1255 else
1256 {
1257 phosphor::logging::log<phosphor::logging::level::INFO>(
1258 "Slot Power is already in 'On' state\n");
1259 return -1;
1260 }
1261 return 0;
1262}
1263static int slotPowerOff()
1264{
1265 if (power_control::slotPowerState != power_control::SlotPowerState::off)
1266 {
1267 slotPowerLine.set_value(0);
1268
1269 if (!(slotPowerLine.get_value() > 0))
1270 {
1271 setSlotPowerState(SlotPowerState::off);
1272 setPowerState(PowerState::off);
1273 phosphor::logging::log<phosphor::logging::level::INFO>(
1274 "Slot Power is switched Off\n");
1275 }
1276 else
1277 {
1278 return -1;
1279 }
1280 }
1281 else
1282 {
1283 phosphor::logging::log<phosphor::logging::level::INFO>(
1284 "Slot Power is already in 'Off' state\n");
1285 return -1;
1286 }
1287 return 0;
1288}
1289static void slotPowerCycle()
1290{
1291 phosphor::logging::log<phosphor::logging::level::INFO>(
1292 "Slot Power Cycle started\n");
1293 slotPowerOff();
1294 slotPowerCycleTimer.expires_after(
1295 std::chrono::milliseconds(TimerMap["slotPowerCycleTimeMs"]));
1296 slotPowerCycleTimer.async_wait([](const boost::system::error_code ec) {
1297 if (ec)
1298 {
1299 if (ec != boost::asio::error::operation_aborted)
1300 {
1301 std::string errMsg =
1302 "Slot Power cycle timer async_wait failed: " + ec.message();
1303 phosphor::logging::log<phosphor::logging::level::ERR>(
1304 errMsg.c_str());
1305 }
1306 phosphor::logging::log<phosphor::logging::level::INFO>(
1307 "Slot Power cycle timer canceled\n");
1308 return;
1309 }
1310 phosphor::logging::log<phosphor::logging::level::INFO>(
1311 "Slot Power cycle timer completed\n");
1312 slotPowerOn();
1313 phosphor::logging::log<phosphor::logging::level::INFO>(
1314 "Slot Power Cycle Completed\n");
1315 });
1316}
1317#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001318static void gracefulPowerOff()
1319{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001320 setGPIOOutputForMs(powerOutConfig, 0, TimerMap["powerPulseTimeMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001321}
1322
1323static void forcePowerOff()
1324{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001325 if (setGPIOOutputForMs(powerOutConfig, 0, TimerMap["forceOffPulseTimeMs"]) <
1326 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001327 {
1328 return;
1329 }
1330
1331 // If the force off timer expires, then the PCH power-button override
1332 // failed, so attempt the Unconditional Powerdown SMBus command.
1333 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1334 if (ec)
1335 {
1336 // operation_aborted is expected if timer is canceled before
1337 // completion.
1338 if (ec != boost::asio::error::operation_aborted)
1339 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001340 std::string errMsg =
1341 "Force power off async_wait failed: " + ec.message();
1342 phosphor::logging::log<phosphor::logging::level::ERR>(
1343 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001344 }
1345 return;
1346 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001347
1348 phosphor::logging::log<phosphor::logging::level::INFO>(
1349 "PCH Power-button override failed. Issuing Unconditional Powerdown "
1350 "SMBus command.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001351 const static constexpr size_t pchDevBusAddress = 3;
1352 const static constexpr size_t pchDevSlaveAddress = 0x44;
1353 const static constexpr size_t pchCmdReg = 0;
1354 const static constexpr size_t pchPowerDownCmd = 0x02;
1355 if (i2cSet(pchDevBusAddress, pchDevSlaveAddress, pchCmdReg,
1356 pchPowerDownCmd) < 0)
1357 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001358 phosphor::logging::log<phosphor::logging::level::ERR>(
1359 "Unconditional Powerdown command failed! Not sure what to do "
1360 "now.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001361 }
1362 });
1363}
1364
1365static void reset()
1366{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001367 setGPIOOutputForMs(resetOutConfig, 0, TimerMap["resetPulseTimeMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001368}
1369
1370static void gracefulPowerOffTimerStart()
1371{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001372 phosphor::logging::log<phosphor::logging::level::INFO>(
1373 "Graceful power-off timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001374 gracefulPowerOffTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301375 std::chrono::seconds(TimerMap["gracefulPowerOffTimeS"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001376 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1377 if (ec)
1378 {
1379 // operation_aborted is expected if timer is canceled before
1380 // completion.
1381 if (ec != boost::asio::error::operation_aborted)
1382 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001383 std::string errMsg =
1384 "Graceful power-off async_wait failed: " + ec.message();
1385 phosphor::logging::log<phosphor::logging::level::ERR>(
1386 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001387 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001388 phosphor::logging::log<phosphor::logging::level::INFO>(
1389 "Graceful power-off timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001390 return;
1391 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001392 phosphor::logging::log<phosphor::logging::level::INFO>(
1393 "Graceful power-off timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001394 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1395 });
1396}
1397
1398static void powerCycleTimerStart()
1399{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001400 phosphor::logging::log<phosphor::logging::level::INFO>(
1401 "Power-cycle timer started");
Priyatharshan P70120512020-09-16 18:47:20 +05301402 powerCycleTimer.expires_after(
1403 std::chrono::milliseconds(TimerMap["powerCycleTimeMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001404 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1405 if (ec)
1406 {
1407 // operation_aborted is expected if timer is canceled before
1408 // completion.
1409 if (ec != boost::asio::error::operation_aborted)
1410 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001411 std::string errMsg =
1412 "Power-cycle async_wait failed: " + ec.message();
1413 phosphor::logging::log<phosphor::logging::level::ERR>(
1414 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001415 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001416 phosphor::logging::log<phosphor::logging::level::INFO>(
1417 "Power-cycle timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001418 return;
1419 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001420 phosphor::logging::log<phosphor::logging::level::INFO>(
1421 "Power-cycle timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001422 sendPowerControlEvent(Event::powerCycleTimerExpired);
1423 });
1424}
1425
1426static void psPowerOKWatchdogTimerStart()
1427{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001428 phosphor::logging::log<phosphor::logging::level::INFO>(
1429 "power supply power OK watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001430 psPowerOKWatchdogTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301431 std::chrono::milliseconds(TimerMap["psPowerOKWatchdogTimeMs"]));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001432 psPowerOKWatchdogTimer.async_wait([](const boost::system::error_code ec) {
1433 if (ec)
1434 {
1435 // operation_aborted is expected if timer is canceled before
1436 // completion.
1437 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001438 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001439 std::string errMsg =
1440 "power supply power OK watchdog async_wait failed: " +
1441 ec.message();
1442 phosphor::logging::log<phosphor::logging::level::ERR>(
1443 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001444 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001445 phosphor::logging::log<phosphor::logging::level::INFO>(
1446 "power supply power OK watchdog timer canceled");
1447 return;
1448 }
1449 phosphor::logging::log<phosphor::logging::level::INFO>(
1450 "power supply power OK watchdog timer expired");
1451 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1452 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001453}
1454
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001455static void warmResetCheckTimerStart()
1456{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001457 phosphor::logging::log<phosphor::logging::level::INFO>(
1458 "Warm reset check timer started");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001459 warmResetCheckTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301460 std::chrono::milliseconds(TimerMap["warmResetCheckTimeMs"]));
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001461 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1462 if (ec)
1463 {
1464 // operation_aborted is expected if timer is canceled before
1465 // completion.
1466 if (ec != boost::asio::error::operation_aborted)
1467 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001468 std::string errMsg =
1469 "Warm reset check async_wait failed: " + ec.message();
1470 phosphor::logging::log<phosphor::logging::level::ERR>(
1471 errMsg.c_str());
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001472 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001473 phosphor::logging::log<phosphor::logging::level::INFO>(
1474 "Warm reset check timer canceled");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001475 return;
1476 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001477 phosphor::logging::log<phosphor::logging::level::INFO>(
1478 "Warm reset check timer completed");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001479 sendPowerControlEvent(Event::warmResetDetected);
1480 });
1481}
1482
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001483static void pohCounterTimerStart()
1484{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001485 phosphor::logging::log<phosphor::logging::level::INFO>("POH timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001486 // Set the time-out as 1 hour, to align with POH command in ipmid
1487 pohCounterTimer.expires_after(std::chrono::hours(1));
1488 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1489 if (ec)
1490 {
1491 // operation_aborted is expected if timer is canceled before
1492 // completion.
1493 if (ec != boost::asio::error::operation_aborted)
1494 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001495 std::string errMsg =
1496 "POH timer async_wait failed: " + ec.message();
1497 phosphor::logging::log<phosphor::logging::level::ERR>(
1498 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001499 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001500 phosphor::logging::log<phosphor::logging::level::INFO>(
1501 "POH timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001502 return;
1503 }
1504
1505 if (getHostState(powerState) !=
1506 "xyz.openbmc_project.State.Host.HostState.Running")
1507 {
1508 return;
1509 }
1510
1511 conn->async_method_call(
1512 [](boost::system::error_code ec,
1513 const std::variant<uint32_t>& pohCounterProperty) {
1514 if (ec)
1515 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001516 phosphor::logging::log<phosphor::logging::level::INFO>(
1517 "error to get poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001518 return;
1519 }
1520 const uint32_t* pohCounter =
1521 std::get_if<uint32_t>(&pohCounterProperty);
1522 if (pohCounter == nullptr)
1523 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001524 phosphor::logging::log<phosphor::logging::level::INFO>(
1525 "unable to read poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001526 return;
1527 }
1528
1529 conn->async_method_call(
1530 [](boost::system::error_code ec) {
1531 if (ec)
1532 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001533 phosphor::logging::log<
1534 phosphor::logging::level::INFO>(
1535 "failed to set poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001536 }
1537 },
1538 "xyz.openbmc_project.Settings",
1539 "/xyz/openbmc_project/state/chassis0",
1540 "org.freedesktop.DBus.Properties", "Set",
1541 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1542 std::variant<uint32_t>(*pohCounter + 1));
1543 },
1544 "xyz.openbmc_project.Settings",
1545 "/xyz/openbmc_project/state/chassis0",
1546 "org.freedesktop.DBus.Properties", "Get",
1547 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1548
1549 pohCounterTimerStart();
1550 });
1551}
1552
1553static void currentHostStateMonitor()
1554{
Yong Li8d660212019-12-27 10:18:10 +08001555 if (getHostState(powerState) ==
1556 "xyz.openbmc_project.State.Host.HostState.Running")
1557 {
1558 pohCounterTimerStart();
1559 // Clear the restart cause set for the next restart
1560 clearRestartCause();
1561 }
1562 else
1563 {
1564 pohCounterTimer.cancel();
1565 // Set the restart cause set for this restart
1566 setRestartCause();
1567 }
1568
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001569 static auto match = sdbusplus::bus::match::match(
1570 *conn,
1571 "type='signal',member='PropertiesChanged', "
1572 "interface='org.freedesktop.DBus.Properties', "
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001573 "arg0='xyz.openbmc_project.State.Host'",
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001574 [](sdbusplus::message::message& message) {
1575 std::string intfName;
1576 std::map<std::string, std::variant<std::string>> properties;
1577
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001578 try
1579 {
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001580 message.read(intfName, properties);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001581 }
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001582 catch (std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001583 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001584 phosphor::logging::log<phosphor::logging::level::ERR>(
1585 "Unable to read host state");
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001586 return;
1587 }
1588 if (properties.empty())
1589 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001590 phosphor::logging::log<phosphor::logging::level::ERR>(
1591 "ERROR: Empty PropertiesChanged signal received");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001592 return;
1593 }
1594
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001595 // We only want to check for CurrentHostState
1596 if (properties.begin()->first != "CurrentHostState")
1597 {
1598 return;
1599 }
1600 std::string* currentHostState =
1601 std::get_if<std::string>(&(properties.begin()->second));
1602 if (currentHostState == nullptr)
1603 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001604 std::string errMsg =
1605 properties.begin()->first + " property invalid";
1606 phosphor::logging::log<phosphor::logging::level::ERR>(
1607 errMsg.c_str());
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001608 return;
1609 }
1610
1611 if (*currentHostState ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001612 "xyz.openbmc_project.State.Host.HostState.Running")
1613 {
1614 pohCounterTimerStart();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001615 // Clear the restart cause set for the next restart
1616 clearRestartCause();
Yong Li8d660212019-12-27 10:18:10 +08001617 sd_journal_send("MESSAGE=Host system DC power is on",
1618 "PRIORITY=%i", LOG_INFO,
1619 "REDFISH_MESSAGE_ID=%s",
1620 "OpenBMC.0.1.DCPowerOn", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001621 }
1622 else
1623 {
1624 pohCounterTimer.cancel();
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301625 // POST_COMPLETE GPIO event is not working in some platforms
1626 // when power state is changed to OFF. This resulted in
1627 // 'OperatingSystemState' to stay at 'Standby', even though
1628 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1629 // if HostState is trurned to OFF.
1630 osIface->set_property("OperatingSystemState",
1631 std::string("Inactive"));
1632
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001633 // Set the restart cause set for this restart
1634 setRestartCause();
Rashmi RV89f61312020-01-22 15:41:50 +05301635 resetACBootProperty();
Yong Li8d660212019-12-27 10:18:10 +08001636 sd_journal_send("MESSAGE=Host system DC power is off",
1637 "PRIORITY=%i", LOG_INFO,
1638 "REDFISH_MESSAGE_ID=%s",
1639 "OpenBMC.0.1.DCPowerOff", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001640 }
1641 });
1642}
1643
1644static void sioPowerGoodWatchdogTimerStart()
1645{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001646 phosphor::logging::log<phosphor::logging::level::INFO>(
1647 "SIO power good watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001648 sioPowerGoodWatchdogTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301649 std::chrono::milliseconds(TimerMap["sioPowerGoodWatchdogTimeMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001650 sioPowerGoodWatchdogTimer.async_wait(
1651 [](const boost::system::error_code ec) {
1652 if (ec)
1653 {
1654 // operation_aborted is expected if timer is canceled before
1655 // completion.
1656 if (ec != boost::asio::error::operation_aborted)
1657 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001658 std::string errMsg =
1659 "SIO power good watchdog async_wait failed: " +
1660 ec.message();
1661 phosphor::logging::log<phosphor::logging::level::ERR>(
1662 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001663 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001664 phosphor::logging::log<phosphor::logging::level::INFO>(
1665 "SIO power good watchdog timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001666 return;
1667 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001668 phosphor::logging::log<phosphor::logging::level::INFO>(
1669 "SIO power good watchdog timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001670 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1671 });
1672}
1673
1674static void powerStateOn(const Event event)
1675{
1676 logEvent(__FUNCTION__, event);
1677 switch (event)
1678 {
1679 case Event::psPowerOKDeAssert:
1680 setPowerState(PowerState::off);
1681 // DC power is unexpectedly lost, beep
1682 beep(beepPowerFail);
1683 break;
1684 case Event::sioS5Assert:
1685 setPowerState(PowerState::transitionToOff);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001686 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001687 break;
Jason M. Billsfb957332021-01-28 13:18:46 -08001688#if USE_PLT_RST
1689 case Event::pltRstAssert:
1690#else
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001691 case Event::postCompleteDeAssert:
Jason M. Billsfb957332021-01-28 13:18:46 -08001692#endif
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001693 setPowerState(PowerState::checkForWarmReset);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001694 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001695 warmResetCheckTimerStart();
1696 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001697 case Event::powerButtonPressed:
1698 setPowerState(PowerState::gracefulTransitionToOff);
1699 gracefulPowerOffTimerStart();
1700 break;
1701 case Event::powerOffRequest:
1702 setPowerState(PowerState::transitionToOff);
1703 forcePowerOff();
1704 break;
1705 case Event::gracefulPowerOffRequest:
1706 setPowerState(PowerState::gracefulTransitionToOff);
1707 gracefulPowerOffTimerStart();
1708 gracefulPowerOff();
1709 break;
1710 case Event::powerCycleRequest:
1711 setPowerState(PowerState::transitionToCycleOff);
1712 forcePowerOff();
1713 break;
1714 case Event::gracefulPowerCycleRequest:
1715 setPowerState(PowerState::gracefulTransitionToCycleOff);
1716 gracefulPowerOffTimerStart();
1717 gracefulPowerOff();
1718 break;
1719 case Event::resetRequest:
1720 reset();
1721 break;
1722 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001723 phosphor::logging::log<phosphor::logging::level::INFO>(
1724 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001725 break;
1726 }
1727}
1728
1729static void powerStateWaitForPSPowerOK(const Event event)
1730{
1731 logEvent(__FUNCTION__, event);
1732 switch (event)
1733 {
1734 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301735 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001736 // Cancel any GPIO assertions held during the transition
1737 gpioAssertTimer.cancel();
1738 psPowerOKWatchdogTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301739 if (sioEnabled == true)
1740 {
1741 sioPowerGoodWatchdogTimerStart();
1742 setPowerState(PowerState::waitForSIOPowerGood);
1743 }
1744 else
1745 {
1746 setPowerState(PowerState::on);
1747 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001748 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301749 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001750 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001751 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001752 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001753 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001754 case Event::sioPowerGoodAssert:
1755 psPowerOKWatchdogTimer.cancel();
1756 setPowerState(PowerState::on);
1757 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001758 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001759 phosphor::logging::log<phosphor::logging::level::INFO>(
1760 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001761 break;
1762 }
1763}
1764
1765static void powerStateWaitForSIOPowerGood(const Event event)
1766{
1767 logEvent(__FUNCTION__, event);
1768 switch (event)
1769 {
1770 case Event::sioPowerGoodAssert:
1771 sioPowerGoodWatchdogTimer.cancel();
1772 setPowerState(PowerState::on);
1773 break;
1774 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001775 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001776 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001777 break;
1778 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001779 phosphor::logging::log<phosphor::logging::level::INFO>(
1780 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001781 break;
1782 }
1783}
1784
1785static void powerStateOff(const Event event)
1786{
1787 logEvent(__FUNCTION__, event);
1788 switch (event)
1789 {
1790 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301791 {
1792 if (sioEnabled == true)
1793 {
1794 setPowerState(PowerState::waitForSIOPowerGood);
1795 }
1796 else
1797 {
1798 setPowerState(PowerState::on);
1799 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001800 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301801 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001802 case Event::sioS5DeAssert:
1803 setPowerState(PowerState::waitForPSPowerOK);
1804 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001805 case Event::sioPowerGoodAssert:
1806 setPowerState(PowerState::on);
1807 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001808 case Event::powerButtonPressed:
1809 psPowerOKWatchdogTimerStart();
1810 setPowerState(PowerState::waitForPSPowerOK);
1811 break;
1812 case Event::powerOnRequest:
1813 psPowerOKWatchdogTimerStart();
1814 setPowerState(PowerState::waitForPSPowerOK);
1815 powerOn();
1816 break;
1817 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001818 phosphor::logging::log<phosphor::logging::level::INFO>(
1819 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001820 break;
1821 }
1822}
1823
1824static void powerStateTransitionToOff(const Event event)
1825{
1826 logEvent(__FUNCTION__, event);
1827 switch (event)
1828 {
1829 case Event::psPowerOKDeAssert:
1830 // Cancel any GPIO assertions held during the transition
1831 gpioAssertTimer.cancel();
1832 setPowerState(PowerState::off);
1833 break;
1834 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001835 phosphor::logging::log<phosphor::logging::level::INFO>(
1836 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001837 break;
1838 }
1839}
1840
1841static void powerStateGracefulTransitionToOff(const Event event)
1842{
1843 logEvent(__FUNCTION__, event);
1844 switch (event)
1845 {
1846 case Event::psPowerOKDeAssert:
1847 gracefulPowerOffTimer.cancel();
1848 setPowerState(PowerState::off);
1849 break;
1850 case Event::gracefulPowerOffTimerExpired:
1851 setPowerState(PowerState::on);
1852 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001853 case Event::powerOffRequest:
1854 gracefulPowerOffTimer.cancel();
1855 setPowerState(PowerState::transitionToOff);
1856 forcePowerOff();
1857 break;
1858 case Event::powerCycleRequest:
1859 gracefulPowerOffTimer.cancel();
1860 setPowerState(PowerState::transitionToCycleOff);
1861 forcePowerOff();
1862 break;
1863 case Event::resetRequest:
1864 gracefulPowerOffTimer.cancel();
1865 setPowerState(PowerState::on);
1866 reset();
1867 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001868 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001869 phosphor::logging::log<phosphor::logging::level::INFO>(
1870 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001871 break;
1872 }
1873}
1874
1875static void powerStateCycleOff(const Event event)
1876{
1877 logEvent(__FUNCTION__, event);
1878 switch (event)
1879 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001880 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301881 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001882 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301883 if (sioEnabled == true)
1884 {
1885 setPowerState(PowerState::waitForSIOPowerGood);
1886 }
1887 else
1888 {
1889 setPowerState(PowerState::on);
1890 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001891 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301892 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001893 case Event::sioS5DeAssert:
1894 powerCycleTimer.cancel();
1895 setPowerState(PowerState::waitForPSPowerOK);
1896 break;
1897 case Event::powerButtonPressed:
1898 powerCycleTimer.cancel();
1899 psPowerOKWatchdogTimerStart();
1900 setPowerState(PowerState::waitForPSPowerOK);
1901 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001902 case Event::powerCycleTimerExpired:
1903 psPowerOKWatchdogTimerStart();
1904 setPowerState(PowerState::waitForPSPowerOK);
1905 powerOn();
1906 break;
1907 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001908 phosphor::logging::log<phosphor::logging::level::INFO>(
1909 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001910 break;
1911 }
1912}
1913
1914static void powerStateTransitionToCycleOff(const Event event)
1915{
1916 logEvent(__FUNCTION__, event);
1917 switch (event)
1918 {
1919 case Event::psPowerOKDeAssert:
1920 // Cancel any GPIO assertions held during the transition
1921 gpioAssertTimer.cancel();
1922 setPowerState(PowerState::cycleOff);
1923 powerCycleTimerStart();
1924 break;
1925 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001926 phosphor::logging::log<phosphor::logging::level::INFO>(
1927 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001928 break;
1929 }
1930}
1931
1932static void powerStateGracefulTransitionToCycleOff(const Event event)
1933{
1934 logEvent(__FUNCTION__, event);
1935 switch (event)
1936 {
1937 case Event::psPowerOKDeAssert:
1938 gracefulPowerOffTimer.cancel();
1939 setPowerState(PowerState::cycleOff);
1940 powerCycleTimerStart();
1941 break;
1942 case Event::gracefulPowerOffTimerExpired:
1943 setPowerState(PowerState::on);
1944 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001945 case Event::powerOffRequest:
1946 gracefulPowerOffTimer.cancel();
1947 setPowerState(PowerState::transitionToOff);
1948 forcePowerOff();
1949 break;
1950 case Event::powerCycleRequest:
1951 gracefulPowerOffTimer.cancel();
1952 setPowerState(PowerState::transitionToCycleOff);
1953 forcePowerOff();
1954 break;
1955 case Event::resetRequest:
1956 gracefulPowerOffTimer.cancel();
1957 setPowerState(PowerState::on);
1958 reset();
1959 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001960 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001961 phosphor::logging::log<phosphor::logging::level::INFO>(
1962 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001963 break;
1964 }
1965}
1966
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001967static void powerStateCheckForWarmReset(const Event event)
1968{
1969 logEvent(__FUNCTION__, event);
1970 switch (event)
1971 {
1972 case Event::sioS5Assert:
1973 warmResetCheckTimer.cancel();
1974 setPowerState(PowerState::transitionToOff);
1975 break;
1976 case Event::warmResetDetected:
1977 setPowerState(PowerState::on);
1978 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001979 case Event::psPowerOKDeAssert:
1980 warmResetCheckTimer.cancel();
1981 setPowerState(PowerState::off);
1982 // DC power is unexpectedly lost, beep
1983 beep(beepPowerFail);
1984 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001985 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001986 phosphor::logging::log<phosphor::logging::level::INFO>(
1987 "No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001988 break;
1989 }
1990}
1991
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001992static void psPowerOKHandler()
1993{
1994 gpiod::line_event gpioLineEvent = psPowerOKLine.event_read();
1995
1996 Event powerControlEvent =
1997 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
1998 ? Event::psPowerOKAssert
1999 : Event::psPowerOKDeAssert;
2000
2001 sendPowerControlEvent(powerControlEvent);
2002 psPowerOKEvent.async_wait(
2003 boost::asio::posix::stream_descriptor::wait_read,
2004 [](const boost::system::error_code ec) {
2005 if (ec)
2006 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002007 std::string errMsg =
2008 "power supply power OK handler error: " + ec.message();
2009 phosphor::logging::log<phosphor::logging::level::ERR>(
2010 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002011 return;
2012 }
2013 psPowerOKHandler();
2014 });
2015}
2016
2017static void sioPowerGoodHandler()
2018{
2019 gpiod::line_event gpioLineEvent = sioPowerGoodLine.event_read();
2020
2021 Event powerControlEvent =
2022 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
2023 ? Event::sioPowerGoodAssert
2024 : Event::sioPowerGoodDeAssert;
2025
2026 sendPowerControlEvent(powerControlEvent);
2027 sioPowerGoodEvent.async_wait(
2028 boost::asio::posix::stream_descriptor::wait_read,
2029 [](const boost::system::error_code ec) {
2030 if (ec)
2031 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002032 std::string errMsg =
2033 "SIO power good handler error: " + ec.message();
2034 phosphor::logging::log<phosphor::logging::level::ERR>(
2035 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002036 return;
2037 }
2038 sioPowerGoodHandler();
2039 });
2040}
2041
2042static void sioOnControlHandler()
2043{
2044 gpiod::line_event gpioLineEvent = sioOnControlLine.event_read();
2045
2046 bool sioOnControl =
2047 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE;
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002048 std::string logMsg =
2049 "SIO_ONCONTROL value changed: " + std::to_string(sioOnControl);
2050 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002051 sioOnControlEvent.async_wait(
2052 boost::asio::posix::stream_descriptor::wait_read,
2053 [](const boost::system::error_code ec) {
2054 if (ec)
2055 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002056 std::string errMsg =
2057 "SIO ONCONTROL handler error: " + ec.message();
2058 phosphor::logging::log<phosphor::logging::level::ERR>(
2059 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002060 return;
2061 }
2062 sioOnControlHandler();
2063 });
2064}
2065
2066static void sioS5Handler()
2067{
2068 gpiod::line_event gpioLineEvent = sioS5Line.event_read();
2069
2070 Event powerControlEvent =
2071 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE
2072 ? Event::sioS5Assert
2073 : Event::sioS5DeAssert;
2074
2075 sendPowerControlEvent(powerControlEvent);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002076 sioS5Event.async_wait(
2077 boost::asio::posix::stream_descriptor::wait_read,
2078 [](const boost::system::error_code ec) {
2079 if (ec)
2080 {
2081 std::string errMsg = "SIO S5 handler error: " + ec.message();
2082 phosphor::logging::log<phosphor::logging::level::ERR>(
2083 errMsg.c_str());
2084 return;
2085 }
2086 sioS5Handler();
2087 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002088}
2089
2090static void powerButtonHandler()
2091{
2092 gpiod::line_event gpioLineEvent = powerButtonLine.event_read();
2093
2094 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2095 {
2096 powerButtonPressLog();
2097 powerButtonIface->set_property("ButtonPressed", true);
2098 if (!powerButtonMask)
2099 {
2100 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002101 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002102 }
2103 else
2104 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002105 phosphor::logging::log<phosphor::logging::level::INFO>(
2106 "power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002107 }
2108 }
2109 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2110 {
2111 powerButtonIface->set_property("ButtonPressed", false);
2112 }
2113 powerButtonEvent.async_wait(
2114 boost::asio::posix::stream_descriptor::wait_read,
2115 [](const boost::system::error_code ec) {
2116 if (ec)
2117 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002118 std::string errMsg =
2119 "power button handler error: " + ec.message();
2120 phosphor::logging::log<phosphor::logging::level::ERR>(
2121 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002122 return;
2123 }
2124 powerButtonHandler();
2125 });
2126}
2127
2128static void resetButtonHandler()
2129{
2130 gpiod::line_event gpioLineEvent = resetButtonLine.event_read();
2131
2132 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2133 {
2134 resetButtonPressLog();
2135 resetButtonIface->set_property("ButtonPressed", true);
2136 if (!resetButtonMask)
2137 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002138 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002139 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002140 }
2141 else
2142 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002143 phosphor::logging::log<phosphor::logging::level::INFO>(
2144 "reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002145 }
2146 }
2147 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2148 {
2149 resetButtonIface->set_property("ButtonPressed", false);
2150 }
2151 resetButtonEvent.async_wait(
2152 boost::asio::posix::stream_descriptor::wait_read,
2153 [](const boost::system::error_code ec) {
2154 if (ec)
2155 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002156 std::string errMsg =
2157 "reset button handler error: " + ec.message();
2158 phosphor::logging::log<phosphor::logging::level::ERR>(
2159 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002160 return;
2161 }
2162 resetButtonHandler();
2163 });
2164}
2165
Vijay Khemka04175c22020-10-09 14:28:11 -07002166#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002167static constexpr auto systemdBusname = "org.freedesktop.systemd1";
2168static constexpr auto systemdPath = "/org/freedesktop/systemd1";
2169static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
2170static constexpr auto systemTargetName = "chassis-system-reset.target";
2171
2172void systemReset()
2173{
2174 conn->async_method_call(
2175 [](boost::system::error_code ec) {
2176 if (ec)
2177 {
2178 phosphor::logging::log<phosphor::logging::level::ERR>(
2179 "Failed to call chassis system reset",
2180 phosphor::logging::entry("ERR=%s", ec.message().c_str()));
2181 }
2182 },
2183 systemdBusname, systemdPath, systemdInterface, "StartUnit",
2184 systemTargetName, "replace");
2185}
Vijay Khemka04175c22020-10-09 14:28:11 -07002186#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002187
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002188static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002189{
2190 conn->async_method_call(
2191 [](boost::system::error_code ec) {
2192 if (ec)
2193 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002194 phosphor::logging::log<phosphor::logging::level::INFO>(
2195 "failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002196 }
2197 },
Chen Yugang303bd582019-11-01 08:45:06 +08002198 "xyz.openbmc_project.Settings",
2199 "/xyz/openbmc_project/Chassis/Control/NMISource",
2200 "org.freedesktop.DBus.Properties", "Set",
2201 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
2202 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002203}
2204
2205static void nmiReset(void)
2206{
2207 static constexpr const uint8_t value = 1;
2208 const static constexpr int nmiOutPulseTimeMs = 200;
2209
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002210 phosphor::logging::log<phosphor::logging::level::INFO>("NMI out action");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002211 nmiOutLine.set_value(value);
Priyatharshan P70120512020-09-16 18:47:20 +05302212 std::string logMsg =
2213 nmiOutConfig.lineName + " set to " + std::to_string(value);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002214 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002215 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2216 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2217 // restore the NMI_OUT GPIO line back to the opposite value
2218 nmiOutLine.set_value(!value);
Priyatharshan P70120512020-09-16 18:47:20 +05302219 std::string logMsg = nmiOutConfig.lineName + " released";
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002220 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002221 if (ec)
2222 {
2223 // operation_aborted is expected if timer is canceled before
2224 // completion.
2225 if (ec != boost::asio::error::operation_aborted)
2226 {
Priyatharshan P70120512020-09-16 18:47:20 +05302227 std::string errMsg = nmiOutConfig.lineName +
2228 " async_wait failed: " + ec.message();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002229 phosphor::logging::log<phosphor::logging::level::ERR>(
2230 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002231 }
2232 }
2233 });
2234 // log to redfish
2235 nmiDiagIntLog();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002236 phosphor::logging::log<phosphor::logging::level::INFO>(
2237 "NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002238 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002239 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002240}
2241
2242static void nmiSourcePropertyMonitor(void)
2243{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002244 phosphor::logging::log<phosphor::logging::level::INFO>(
2245 "NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002246
2247 static std::unique_ptr<sdbusplus::bus::match::match> nmiSourceMatch =
2248 std::make_unique<sdbusplus::bus::match::match>(
2249 *conn,
2250 "type='signal',interface='org.freedesktop.DBus.Properties',"
Chen Yugang303bd582019-11-01 08:45:06 +08002251 "member='PropertiesChanged',arg0namespace='xyz.openbmc_project."
2252 "Chassis.Control."
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002253 "NMISource'",
2254 [](sdbusplus::message::message& msg) {
2255 std::string interfaceName;
2256 boost::container::flat_map<std::string,
2257 std::variant<bool, std::string>>
2258 propertiesChanged;
2259 std::string state;
2260 bool value = true;
2261 try
2262 {
2263 msg.read(interfaceName, propertiesChanged);
2264 if (propertiesChanged.begin()->first == "Enabled")
2265 {
2266 value =
2267 std::get<bool>(propertiesChanged.begin()->second);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002268 std::string logMsg =
2269 " NMI Enabled propertiesChanged value: " +
2270 std::to_string(value);
2271 phosphor::logging::log<phosphor::logging::level::INFO>(
2272 logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002273 nmiEnabled = value;
2274 if (nmiEnabled)
2275 {
2276 nmiReset();
2277 }
2278 }
2279 }
2280 catch (std::exception& e)
2281 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002282 phosphor::logging::log<phosphor::logging::level::ERR>(
2283 "Unable to read NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002284 return;
2285 }
2286 });
2287}
2288
2289static void setNmiSource()
2290{
2291 conn->async_method_call(
2292 [](boost::system::error_code ec) {
2293 if (ec)
2294 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002295 phosphor::logging::log<phosphor::logging::level::ERR>(
2296 "failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002297 }
2298 },
Chen Yugang303bd582019-11-01 08:45:06 +08002299 "xyz.openbmc_project.Settings",
2300 "/xyz/openbmc_project/Chassis/Control/NMISource",
2301 "org.freedesktop.DBus.Properties", "Set",
2302 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
2303 std::variant<std::string>{"xyz.openbmc_project.Chassis.Control."
2304 "NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002305 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002306 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002307}
2308
2309static void nmiButtonHandler()
2310{
2311 gpiod::line_event gpioLineEvent = nmiButtonLine.event_read();
2312
2313 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2314 {
2315 nmiButtonPressLog();
2316 nmiButtonIface->set_property("ButtonPressed", true);
2317 if (nmiButtonMasked)
2318 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002319 phosphor::logging::log<phosphor::logging::level::INFO>(
2320 "NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002321 }
2322 else
2323 {
2324 setNmiSource();
2325 }
2326 }
2327 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2328 {
2329 nmiButtonIface->set_property("ButtonPressed", false);
2330 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002331 nmiButtonEvent.async_wait(
2332 boost::asio::posix::stream_descriptor::wait_read,
2333 [](const boost::system::error_code ec) {
2334 if (ec)
2335 {
2336 std::string errMsg =
2337 "NMI button handler error: " + ec.message();
2338 phosphor::logging::log<phosphor::logging::level::ERR>(
2339 errMsg.c_str());
2340 return;
2341 }
2342 nmiButtonHandler();
2343 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002344}
2345
2346static void idButtonHandler()
2347{
2348 gpiod::line_event gpioLineEvent = idButtonLine.event_read();
2349
2350 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2351 {
2352 idButtonIface->set_property("ButtonPressed", true);
2353 }
2354 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2355 {
2356 idButtonIface->set_property("ButtonPressed", false);
2357 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002358 idButtonEvent.async_wait(
2359 boost::asio::posix::stream_descriptor::wait_read,
2360 [](const boost::system::error_code& ec) {
2361 if (ec)
2362 {
2363 std::string errMsg = "ID button handler error: " + ec.message();
2364 phosphor::logging::log<phosphor::logging::level::ERR>(
2365 errMsg.c_str());
2366 return;
2367 }
2368 idButtonHandler();
2369 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002370}
2371
Jason M. Billsfb957332021-01-28 13:18:46 -08002372static void pltRstHandler(bool pltRst)
2373{
2374 if (pltRst)
2375 {
2376 sendPowerControlEvent(Event::pltRstDeAssert);
2377 }
2378 else
2379 {
2380 sendPowerControlEvent(Event::pltRstAssert);
2381 }
2382}
2383
2384static void hostMiscHandler(sdbusplus::message::message& msg)
2385{
2386 std::string interfaceName;
2387 boost::container::flat_map<std::string, std::variant<bool>>
2388 propertiesChanged;
2389 bool pltRst;
2390 try
2391 {
2392 msg.read(interfaceName, propertiesChanged);
2393 }
2394 catch (std::exception& e)
2395 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002396 phosphor::logging::log<phosphor::logging::level::ERR>(
2397 "Unable to read Host Misc status");
Jason M. Billsfb957332021-01-28 13:18:46 -08002398 return;
2399 }
2400 if (propertiesChanged.empty())
2401 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002402 phosphor::logging::log<phosphor::logging::level::ERR>(
2403 "ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002404 return;
2405 }
2406
2407 for (auto& [property, value] : propertiesChanged)
2408 {
2409 if (property == "ESpiPlatformReset")
2410 {
2411 bool* pltRst = std::get_if<bool>(&value);
2412 if (pltRst == nullptr)
2413 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002414 std::string errMsg = property + " property invalid";
2415 phosphor::logging::log<phosphor::logging::level::ERR>(
2416 errMsg.c_str());
Jason M. Billsfb957332021-01-28 13:18:46 -08002417 return;
2418 }
2419 pltRstHandler(*pltRst);
2420 }
2421 }
2422}
2423
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002424static void postCompleteHandler()
2425{
2426 gpiod::line_event gpioLineEvent = postCompleteLine.event_read();
2427
2428 bool postComplete =
2429 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002430 if (postComplete)
2431 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002432 sendPowerControlEvent(Event::postCompleteAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002433 osIface->set_property("OperatingSystemState", std::string("Standby"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002434 }
2435 else
2436 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002437 sendPowerControlEvent(Event::postCompleteDeAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002438 osIface->set_property("OperatingSystemState", std::string("Inactive"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002439 }
2440 postCompleteEvent.async_wait(
2441 boost::asio::posix::stream_descriptor::wait_read,
2442 [](const boost::system::error_code ec) {
2443 if (ec)
2444 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002445 std::string errMsg =
2446 "POST complete handler error: " + ec.message();
2447 phosphor::logging::log<phosphor::logging::level::ERR>(
2448 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002449 return;
2450 }
2451 postCompleteHandler();
2452 });
2453}
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302454
2455static int loadConfigValues()
2456{
2457 const std::string configFilePath =
2458 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2459 ".json";
2460 std::ifstream configFile(configFilePath.c_str());
2461 if (!configFile.is_open())
2462 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002463 phosphor::logging::log<phosphor::logging::level::ERR>(
2464 "loadConfigValues : Cannot open config path");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302465 return -1;
2466 }
Zev Weiss1aa08b22021-09-15 17:06:20 -05002467 auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302468
Priyatharshan P70120512020-09-16 18:47:20 +05302469 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302470 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002471 phosphor::logging::log<phosphor::logging::level::ERR>(
2472 "Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302473 return -1;
2474 }
Priyatharshan P70120512020-09-16 18:47:20 +05302475 auto gpios = jsonData["gpio_configs"];
2476 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302477
Priyatharshan P70120512020-09-16 18:47:20 +05302478 ConfigData* tempGpioData;
2479
2480 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302481 {
Priyatharshan P70120512020-09-16 18:47:20 +05302482 if (!gpioConfig.contains("Name"))
2483 {
2484 phosphor::logging::log<phosphor::logging::level::ERR>(
2485 "The 'Name' field must be defined in Json file");
2486 return -1;
2487 }
2488
2489 // Iterate through the powersignal map to check if the gpio json config
2490 // entry is valid
2491 std::string gpioName = gpioConfig["Name"];
2492 auto signalMapIter = powerSignalMap.find(gpioName);
2493 if (signalMapIter == powerSignalMap.end())
2494 {
2495 std::string errMsg = "Undefined Name : " + gpioName;
2496 phosphor::logging::log<phosphor::logging::level::ERR>(
2497 errMsg.c_str());
2498 return -1;
2499 }
2500
2501 // assign the power signal name to the corresponding structure reference
2502 // from map then fillup the structure with coressponding json config
2503 // value
2504 tempGpioData = signalMapIter->second;
2505 tempGpioData->name = gpioName;
2506
2507 if (!gpioConfig.contains("Type"))
2508 {
2509 phosphor::logging::log<phosphor::logging::level::ERR>(
2510 "The \'Type\' field must be defined in Json file");
2511 return -1;
2512 }
2513
2514 std::string signalType = gpioConfig["Type"];
2515 if (signalType == "GPIO")
2516 {
2517 tempGpioData->type = ConfigType::GPIO;
2518 }
2519 else if (signalType == "DBUS")
2520 {
2521 tempGpioData->type = ConfigType::DBUS;
2522 }
2523 else
2524 {
2525 std::string errMsg = "Undefined Type : " + signalType;
2526 phosphor::logging::log<phosphor::logging::level::ERR>(
2527 errMsg.c_str());
2528 return -1;
2529 }
2530
2531 if (tempGpioData->type == ConfigType::GPIO)
2532 {
2533 if (gpioConfig.contains("LineName"))
2534 {
2535 tempGpioData->lineName = gpioConfig["LineName"];
2536 }
2537 else
2538 {
2539 phosphor::logging::log<phosphor::logging::level::ERR>(
2540 "The \'LineName\' field must be defined for GPIO "
2541 "configuration");
2542 return -1;
2543 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002544 if (gpioConfig.contains("Polarity"))
2545 {
2546 std::string polarity = gpioConfig["Polarity"];
2547 if (polarity == "ActiveLow")
2548 {
2549 tempGpioData->polarity = false;
2550 }
2551 else if (polarity == "ActiveHigh")
2552 {
2553 tempGpioData->polarity = true;
2554 }
2555 else
2556 {
2557 std::string errMsg =
2558 "Polarity defined but not properly setup. Please "
2559 "only ActiveHigh or ActiveLow. Currently set to " +
2560 polarity;
2561 phosphor::logging::log<phosphor::logging::level::ERR>(
2562 errMsg.c_str());
2563 return -1;
2564 }
2565 }
2566 else
2567 {
2568 std::string errMsg =
2569 "Polarity field not found for " + tempGpioData->lineName;
2570 phosphor::logging::log<phosphor::logging::level::ERR>(
2571 errMsg.c_str());
2572 return -1;
2573 }
Priyatharshan P70120512020-09-16 18:47:20 +05302574 }
2575 else
2576 {
2577 // if dbus based gpio config is defined read and update the dbus
2578 // params corresponding to the gpio config instance
2579 for (auto& [key, dbusParamName] : dbusParams)
2580 {
2581 if (!gpios.contains(dbusParamName))
2582 {
2583 std::string errMsg =
2584 "The " + dbusParamName +
2585 "field must be defined for Dbus configuration ";
2586 phosphor::logging::log<phosphor::logging::level::ERR>(
2587 errMsg.c_str());
2588 return -1;
2589 }
2590 }
2591 tempGpioData->dbusName = gpios[dbusParams[DbusConfigType::name]];
2592 tempGpioData->path = gpios[dbusParams[DbusConfigType::path]];
2593 tempGpioData->interface =
2594 gpios[dbusParams[DbusConfigType::interface]];
2595 tempGpioData->lineName =
2596 gpios[dbusParams[DbusConfigType::property]];
2597 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302598 }
2599
Priyatharshan P70120512020-09-16 18:47:20 +05302600 // read and store the timer values from json config to Timer Map
2601 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302602 {
Priyatharshan P70120512020-09-16 18:47:20 +05302603 if (timers.contains(key.c_str()))
2604 {
2605 timerValue = timers[key.c_str()];
2606 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302607 }
2608
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302609 return 0;
2610}
Priyatharshan P70120512020-09-16 18:47:20 +05302611inline static sdbusplus::bus::match::match powerButtonEventMonitor()
2612{
2613 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2614 bool value = false;
2615 std::string thresholdInterface;
2616 std::string event;
2617 boost::container::flat_map<std::string, std::variant<bool>>
2618 propertiesChanged;
2619 try
2620 {
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302621
Priyatharshan P70120512020-09-16 18:47:20 +05302622 msg.read(thresholdInterface, propertiesChanged);
2623
2624 if (propertiesChanged.empty())
2625 {
2626 return;
2627 }
2628 event = propertiesChanged.begin()->first;
2629
2630 if (event.empty() || event != powerButtonConfig.lineName)
2631 {
2632 return;
2633 }
2634
2635 value = std::get<bool>(propertiesChanged.begin()->second);
2636 }
2637 catch (std::exception& e)
2638 {
2639 phosphor::logging::log<phosphor::logging::level::ERR>(
2640 "exception during reading dbus property : powerButtonConfig");
2641 return;
2642 }
2643
2644 if (value == false)
2645 {
2646 powerButtonPressLog();
2647 powerButtonIface->set_property("ButtonPressed", true);
2648 if (!powerButtonMask)
2649 {
2650 sendPowerControlEvent(Event::powerButtonPressed);
2651 addRestartCause(RestartCause::powerButton);
2652 }
2653 else
2654 {
2655 phosphor::logging::log<phosphor::logging::level::ERR>(
2656 "power button press masked\n");
2657 }
2658 }
2659 else
2660 {
2661 powerButtonIface->set_property("ButtonPressed", false);
2662 }
2663 };
2664
2665 sdbusplus::bus::match::match pulseEventMatcher(
2666 static_cast<sdbusplus::bus::bus&>(*conn),
2667 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2668 "PropertiesChanged',arg0='" +
2669 powerButtonConfig.dbusName + "'",
2670 std::move(pulseEventMatcherCallback));
2671
2672 return pulseEventMatcher;
2673}
2674
2675inline static sdbusplus::bus::match::match resetButtonEventMonitor()
2676{
2677 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2678 bool value = false;
2679 std::string thresholdInterface;
2680 std::string event;
2681 boost::container::flat_map<std::string, std::variant<bool>>
2682 propertiesChanged;
2683 try
2684 {
2685 msg.read(thresholdInterface, propertiesChanged);
2686
2687 if (propertiesChanged.empty())
2688 {
2689 return;
2690 }
2691 event = propertiesChanged.begin()->first;
2692
2693 if (event.empty() || event != resetButtonConfig.lineName)
2694 {
2695 return;
2696 }
2697
2698 value = std::get<bool>(propertiesChanged.begin()->second);
2699 }
2700 catch (std::exception& e)
2701 {
2702 phosphor::logging::log<phosphor::logging::level::ERR>(
2703 "exception during reading dbus property : resetButtonConfig");
2704 return;
2705 }
2706
2707 if (value == false)
2708 {
2709 resetButtonPressLog();
2710 resetButtonIface->set_property("ButtonPressed", true);
2711 if (!resetButtonMask)
2712 {
2713 sendPowerControlEvent(Event::resetButtonPressed);
2714 addRestartCause(RestartCause::resetButton);
2715 }
2716 else
2717 {
2718 phosphor::logging::log<phosphor::logging::level::ERR>(
2719 "reset button press masked");
2720 }
2721 }
2722 else
2723 {
2724 resetButtonIface->set_property("ButtonPressed", false);
2725 }
2726 };
2727
2728 sdbusplus::bus::match::match pulseEventMatcher(
2729 static_cast<sdbusplus::bus::bus&>(*conn),
2730 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2731 "PropertiesChanged',arg0='" +
2732 resetButtonConfig.dbusName + "'",
2733 std::move(pulseEventMatcherCallback));
2734
2735 return pulseEventMatcher;
2736}
2737
2738inline static sdbusplus::bus::match::match powerOkEventMonitor()
2739{
2740 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2741 bool value = false;
2742 std::string thresholdInterface;
2743 std::string event;
2744 boost::container::flat_map<std::string, std::variant<bool>>
2745 propertiesChanged;
2746 try
2747 {
2748 msg.read(thresholdInterface, propertiesChanged);
2749
2750 if (propertiesChanged.empty())
2751 {
2752 return;
2753 }
2754 event = propertiesChanged.begin()->first;
2755
2756 if (event.empty() || event != powerOkConfig.lineName)
2757 {
2758 return;
2759 }
2760
2761 value = std::get<bool>(propertiesChanged.begin()->second);
2762 }
2763 catch (std::exception& e)
2764 {
2765 phosphor::logging::log<phosphor::logging::level::ERR>(
2766 "exception during reading dbus property : powerOkConfig");
2767 return;
2768 }
2769
2770 Event powerControlEvent =
2771 value ? Event::psPowerOKAssert : Event::psPowerOKDeAssert;
2772 sendPowerControlEvent(powerControlEvent);
2773 };
2774
2775 sdbusplus::bus::match::match pulseEventMatcher(
2776 static_cast<sdbusplus::bus::bus&>(*conn),
2777 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2778 "PropertiesChanged',arg0='" +
2779 powerOkConfig.dbusName + "'",
2780 std::move(pulseEventMatcherCallback));
2781
2782 return pulseEventMatcher;
2783}
2784
2785inline static sdbusplus::bus::match::match sioPwrGoodEventMonitor()
2786{
2787 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2788 bool value = false;
2789 std::string thresholdInterface;
2790 std::string event;
2791 boost::container::flat_map<std::string, std::variant<bool>>
2792 propertiesChanged;
2793 try
2794 {
2795 msg.read(thresholdInterface, propertiesChanged);
2796
2797 if (propertiesChanged.empty())
2798 {
2799 return;
2800 }
2801 event = propertiesChanged.begin()->first;
2802
2803 if (event.empty() || event != sioPwrGoodConfig.lineName)
2804 {
2805 return;
2806 }
2807
2808 value = std::get<bool>(propertiesChanged.begin()->second);
2809 }
2810 catch (std::exception& e)
2811 {
2812 phosphor::logging::log<phosphor::logging::level::ERR>(
2813 "exception during reading dbus property : sioPwrGoodConfig");
2814 return;
2815 }
2816
2817 Event powerControlEvent =
2818 value ? Event::sioPowerGoodAssert : Event::sioPowerGoodDeAssert;
2819
2820 sendPowerControlEvent(powerControlEvent);
2821 };
2822
2823 sdbusplus::bus::match::match pulseEventMatcher(
2824 static_cast<sdbusplus::bus::bus&>(*conn),
2825 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2826 "PropertiesChanged',arg0='" +
2827 sioPwrGoodConfig.dbusName + "'",
2828 std::move(pulseEventMatcherCallback));
2829
2830 return pulseEventMatcher;
2831}
2832
2833inline static sdbusplus::bus::match::match sioOnControlEventMonitor()
2834{
2835 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2836 bool value = false;
2837 std::string thresholdInterface;
2838 std::string event;
2839 boost::container::flat_map<std::string, std::variant<bool>>
2840 propertiesChanged;
2841 try
2842 {
2843 msg.read(thresholdInterface, propertiesChanged);
2844
2845 if (propertiesChanged.empty())
2846 {
2847 return;
2848 }
2849 event = propertiesChanged.begin()->first;
2850
2851 if (event.empty() || event != sioOnControlConfig.lineName)
2852 {
2853 return;
2854 }
2855
2856 value = std::get<bool>(propertiesChanged.begin()->second);
2857 }
2858 catch (std::exception& e)
2859 {
2860 phosphor::logging::log<phosphor::logging::level::ERR>(
2861 "exception during reading dbus property : sioOnControlConfig");
2862 return;
2863 }
2864
2865 std::string errMsg =
2866 "SIO_ONCONTROL value changed : " + std::to_string(value);
2867 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
2868 };
2869
2870 sdbusplus::bus::match::match pulseEventMatcher(
2871 static_cast<sdbusplus::bus::bus&>(*conn),
2872 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2873 "PropertiesChanged',arg0='" +
2874 sioOnControlConfig.dbusName + "'",
2875 std::move(pulseEventMatcherCallback));
2876
2877 return pulseEventMatcher;
2878}
2879
2880inline static sdbusplus::bus::match::match sioS5EventMonitor()
2881{
2882 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2883 bool value = false;
2884 std::string thresholdInterface;
2885 std::string event;
2886 boost::container::flat_map<std::string, std::variant<bool>>
2887 propertiesChanged;
2888 try
2889 {
2890 msg.read(thresholdInterface, propertiesChanged);
2891
2892 if (propertiesChanged.empty())
2893 {
2894 return;
2895 }
2896 event = propertiesChanged.begin()->first;
2897
2898 if (event.empty() || event != sioS5Config.lineName)
2899 {
2900 return;
2901 }
2902
2903 value = std::get<bool>(propertiesChanged.begin()->second);
2904 }
2905 catch (std::exception& e)
2906 {
2907 phosphor::logging::log<phosphor::logging::level::ERR>(
2908 "exception during reading dbus property : sioS5Config");
2909 return;
2910 }
2911
2912 Event powerControlEvent =
2913 value ? Event::sioS5DeAssert : Event::sioS5Assert;
2914 sendPowerControlEvent(powerControlEvent);
2915 };
2916
2917 sdbusplus::bus::match::match pulseEventMatcher(
2918 static_cast<sdbusplus::bus::bus&>(*conn),
2919 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2920 "PropertiesChanged',arg0='" +
2921 sioS5Config.dbusName + "'",
2922 std::move(pulseEventMatcherCallback));
2923
2924 return pulseEventMatcher;
2925}
2926
2927inline static sdbusplus::bus::match::match nmiButtonEventMonitor()
2928{
2929 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2930 bool value = false;
2931 std::string thresholdInterface;
2932 std::string event;
2933 boost::container::flat_map<std::string, std::variant<bool>>
2934 propertiesChanged;
2935 try
2936 {
2937 msg.read(thresholdInterface, propertiesChanged);
2938
2939 if (propertiesChanged.empty())
2940 {
2941 return;
2942 }
2943 event = propertiesChanged.begin()->first;
2944 if (event.empty() || event != nmiButtonConfig.lineName)
2945 {
2946 return;
2947 }
2948
2949 value = std::get<bool>(propertiesChanged.begin()->second);
2950 }
2951 catch (std::exception& e)
2952 {
2953 phosphor::logging::log<phosphor::logging::level::ERR>(
2954 "exception during reading dbus property : nmiButtonConfig");
2955 return;
2956 }
2957
2958 if (value)
2959 {
2960 nmiButtonIface->set_property("ButtonPressed", false);
2961 }
2962 else
2963 {
2964 nmiButtonPressLog();
2965 nmiButtonIface->set_property("ButtonPressed", true);
2966 if (nmiButtonMasked)
2967 {
2968 phosphor::logging::log<phosphor::logging::level::ERR>(
2969 "NMI button press masked");
2970 }
2971 else
2972 {
2973 setNmiSource();
2974 }
2975 }
2976 };
2977
2978 sdbusplus::bus::match::match pulseEventMatcher(
2979 static_cast<sdbusplus::bus::bus&>(*conn),
2980 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2981 "PropertiesChanged',arg0='" +
2982 nmiButtonConfig.dbusName + "'",
2983 std::move(pulseEventMatcherCallback));
2984
2985 return pulseEventMatcher;
2986}
2987
2988inline static sdbusplus::bus::match::match idButtonEventMonitor()
2989{
2990 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2991 bool value = false;
2992 std::string thresholdInterface;
2993 std::string event;
2994 boost::container::flat_map<std::string, std::variant<bool>>
2995 propertiesChanged;
2996
2997 try
2998 {
2999
3000 msg.read(thresholdInterface, propertiesChanged);
3001
3002 if (propertiesChanged.empty())
3003 {
3004 return;
3005 }
3006 event = propertiesChanged.begin()->first;
3007
3008 if (event.empty() | event != idButtonConfig.lineName)
3009 {
3010 return;
3011 }
3012
3013 value = std::get<bool>(propertiesChanged.begin()->second);
3014 }
3015 catch (std::exception& e)
3016 {
3017 phosphor::logging::log<phosphor::logging::level::ERR>(
3018 "exception during reading dbus property : idButtonConfig");
3019 return;
3020 }
3021
3022 if (value)
3023 {
3024 idButtonIface->set_property("ButtonPressed", false);
3025 }
3026 else
3027 {
3028 idButtonIface->set_property("ButtonPressed", true);
3029 }
3030 };
3031
3032 sdbusplus::bus::match::match pulseEventMatcher(
3033 static_cast<sdbusplus::bus::bus&>(*conn),
3034 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
3035 "PropertiesChanged',arg0='" +
3036 idButtonConfig.dbusName + "'",
3037 std::move(pulseEventMatcherCallback));
3038
3039 return pulseEventMatcher;
3040}
3041
3042inline static sdbusplus::bus::match::match postCompleteEventMonitor()
3043{
3044 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
3045 bool value = false;
3046 std::string thresholdInterface;
3047 std::string event;
3048 boost::container::flat_map<std::string, std::variant<bool>>
3049 propertiesChanged;
3050 try
3051 {
3052
3053 msg.read(thresholdInterface, propertiesChanged);
3054
3055 if (propertiesChanged.empty())
3056 {
3057 return;
3058 }
3059 event = propertiesChanged.begin()->first;
3060
3061 if (event.empty() | event != postCompleteConfig.lineName)
3062 {
3063 return;
3064 }
3065
3066 value = std::get<bool>(propertiesChanged.begin()->second);
3067 }
3068 catch (std::exception& e)
3069 {
3070 phosphor::logging::log<phosphor::logging::level::ERR>(
3071 "exception during reading dbus property : postCompleteConfig");
3072 return;
3073 }
3074
3075 if (value)
3076 {
3077 sendPowerControlEvent(Event::postCompleteDeAssert);
3078 osIface->set_property("OperatingSystemState",
3079 std::string("Inactive"));
3080 }
3081 else
3082 {
3083 sendPowerControlEvent(Event::postCompleteAssert);
3084 osIface->set_property("OperatingSystemState",
3085 std::string("Standby"));
3086 }
3087 };
3088
3089 sdbusplus::bus::match::match pulseEventMatcher(
3090 static_cast<sdbusplus::bus::bus&>(*conn),
3091 "type='signal',path='" + postCompleteConfig.path +
3092 "',interface='org.freedesktop.DBus.Properties',member='"
3093 "PropertiesChanged',arg0='" +
3094 postCompleteConfig.dbusName + "'",
3095 std::move(pulseEventMatcherCallback));
3096
3097 return pulseEventMatcher;
3098}
3099
3100int getProperty(ConfigData& configData)
3101{
3102 auto method = conn->new_method_call(
3103 configData.dbusName.c_str(), configData.path.c_str(),
3104 "org.freedesktop.DBus.Properties", "Get");
3105 method.append(configData.interface.c_str(), configData.lineName.c_str());
3106
3107 auto reply = conn->call(method);
3108 if (reply.is_method_error())
3109 {
3110 phosphor::logging::log<phosphor::logging::level::ERR>(
3111 "Error reading from Bus");
3112 return -1;
3113 }
3114 std::variant<int> resp;
3115 reply.read(resp);
3116 auto respValue = std::get_if<int>(&resp);
3117 if (!respValue)
3118 {
3119 phosphor::logging::log<phosphor::logging::level::ERR>(
3120 "Error reading response");
3121 return -1;
3122 }
3123 return (*respValue);
3124}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003125} // namespace power_control
3126
3127int main(int argc, char* argv[])
3128{
Lei YU92caa4c2021-02-23 16:59:25 +08003129 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05303130
3131 if (argc > 1)
3132 {
3133 node = argv[1];
3134 }
3135 std::string infoMsg =
3136 "Start Chassis power control service for host : " + node;
3137 phosphor::logging::log<phosphor::logging::level::INFO>(infoMsg.c_str());
3138
Lei YU92caa4c2021-02-23 16:59:25 +08003139 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003140
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303141 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08003142 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303143 {
Lei YU92caa4c2021-02-23 16:59:25 +08003144 std::string errMsg = "Host" + node + ": " + "Error in Parsing...";
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003145 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303146 }
Naveen Mosesec972d82021-07-16 21:19:23 +05303147 /* Currently for single host based systems additional busname is added
3148 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
3149 Going forward for single hosts the old bus name without zero numbering
3150 will be removed when all other applications adapted to the
3151 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
3152
3153 if (node == "0")
3154 {
3155 // Request all the dbus names
3156 conn->request_name(hostDbusName.c_str());
3157 conn->request_name(chassisDbusName.c_str());
3158 conn->request_name(osDbusName.c_str());
3159 conn->request_name(buttonDbusName.c_str());
3160 conn->request_name(nmiDbusName.c_str());
3161 conn->request_name(rstCauseDbusName.c_str());
3162 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303163
Zev Weissc4005bd2021-09-01 22:30:23 -05003164 hostDbusName += node;
3165 chassisDbusName += node;
3166 osDbusName += node;
3167 buttonDbusName += node;
3168 nmiDbusName += node;
3169 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003170
Priyatharshan P70120512020-09-16 18:47:20 +05303171 // Request all the dbus names
3172 conn->request_name(hostDbusName.c_str());
3173 conn->request_name(chassisDbusName.c_str());
3174 conn->request_name(osDbusName.c_str());
3175 conn->request_name(buttonDbusName.c_str());
3176 conn->request_name(nmiDbusName.c_str());
3177 conn->request_name(rstCauseDbusName.c_str());
3178
3179 if (sioPwrGoodConfig.lineName.empty() ||
3180 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05303181 {
Lei YU92caa4c2021-02-23 16:59:25 +08003182 sioEnabled = false;
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003183 phosphor::logging::log<phosphor::logging::level::INFO>(
3184 "SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05303185 }
3186
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003187 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303188 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003189 {
Priyatharshan P70120512020-09-16 18:47:20 +05303190 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
3191 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303192 {
3193 return -1;
3194 }
3195 }
Priyatharshan P70120512020-09-16 18:47:20 +05303196 else if (powerOkConfig.type == ConfigType::DBUS)
3197 {
3198
3199 static sdbusplus::bus::match::match powerOkEventMonitor =
3200 power_control::powerOkEventMonitor();
3201 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303202 else
3203 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003204 phosphor::logging::log<phosphor::logging::level::ERR>(
3205 "PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003206 return -1;
3207 }
3208
Lei YU92caa4c2021-02-23 16:59:25 +08003209 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003210 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05303211 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303212 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303213 {
Priyatharshan P70120512020-09-16 18:47:20 +05303214 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
3215 sioPowerGoodHandler, sioPowerGoodLine,
3216 sioPowerGoodEvent))
3217 {
3218 return -1;
3219 }
3220 }
3221 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
3222 {
3223 static sdbusplus::bus::match::match sioPwrGoodEventMonitor =
3224 power_control::sioPwrGoodEventMonitor();
3225 }
3226 else
3227 {
3228 phosphor::logging::log<phosphor::logging::level::ERR>(
3229 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303230 return -1;
3231 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003232
Priyatharshan P19c47a32020-08-12 18:16:43 +05303233 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303234 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303235 {
Priyatharshan P70120512020-09-16 18:47:20 +05303236 if (!requestGPIOEvents(sioOnControlConfig.lineName,
3237 sioOnControlHandler, sioOnControlLine,
3238 sioOnControlEvent))
3239 {
3240 return -1;
3241 }
3242 }
3243 else if (sioOnControlConfig.type == ConfigType::DBUS)
3244 {
3245 static sdbusplus::bus::match::match sioOnControlEventMonitor =
3246 power_control::sioOnControlEventMonitor();
3247 }
3248 else
3249 {
3250 phosphor::logging::log<phosphor::logging::level::ERR>(
3251 "sioOnControl name should be configured from json"
3252 "config file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303253 return -1;
3254 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003255
Priyatharshan P19c47a32020-08-12 18:16:43 +05303256 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303257 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303258 {
Priyatharshan P70120512020-09-16 18:47:20 +05303259 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
3260 sioS5Line, sioS5Event))
3261 {
3262 return -1;
3263 }
3264 }
3265 else if (sioS5Config.type == ConfigType::DBUS)
3266 {
3267 static sdbusplus::bus::match::match sioS5EventMonitor =
3268 power_control::sioS5EventMonitor();
3269 }
3270 else
3271 {
3272 phosphor::logging::log<phosphor::logging::level::ERR>(
3273 "sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303274 return -1;
3275 }
3276 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003277
3278 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303279 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003280 {
Priyatharshan P70120512020-09-16 18:47:20 +05303281 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
Lei YU92caa4c2021-02-23 16:59:25 +08003282 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303283 {
3284 return -1;
3285 }
3286 }
Priyatharshan P70120512020-09-16 18:47:20 +05303287 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303288 {
Priyatharshan P70120512020-09-16 18:47:20 +05303289 static sdbusplus::bus::match::match powerButtonEventMonitor =
3290 power_control::powerButtonEventMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003291 }
3292
3293 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303294 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003295 {
Priyatharshan P70120512020-09-16 18:47:20 +05303296 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
Lei YU92caa4c2021-02-23 16:59:25 +08003297 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303298 {
3299 return -1;
3300 }
3301 }
Priyatharshan P70120512020-09-16 18:47:20 +05303302 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303303 {
Priyatharshan P70120512020-09-16 18:47:20 +05303304 static sdbusplus::bus::match::match resetButtonEventMonitor =
3305 power_control::resetButtonEventMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003306 }
3307
3308 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303309 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303310 {
Priyatharshan P70120512020-09-16 18:47:20 +05303311 if (!nmiButtonConfig.lineName.empty())
3312 {
3313 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
3314 nmiButtonLine, nmiButtonEvent);
3315 }
3316 }
3317 else if (nmiButtonConfig.type == ConfigType::DBUS)
3318 {
3319 static sdbusplus::bus::match::match nmiButtonEventMonitor =
3320 power_control::nmiButtonEventMonitor();
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303321 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003322
3323 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303324 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303325 {
Priyatharshan P70120512020-09-16 18:47:20 +05303326 if (!idButtonConfig.lineName.empty())
3327 {
3328 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
3329 idButtonLine, idButtonEvent);
3330 }
3331 }
3332 else if (idButtonConfig.type == ConfigType::DBUS)
3333 {
3334 static sdbusplus::bus::match::match idButtonEventMonitor =
3335 power_control::idButtonEventMonitor();
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303336 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003337
Jason M. Billsfb957332021-01-28 13:18:46 -08003338#ifdef USE_PLT_RST
3339 sdbusplus::bus::match::match pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08003340 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08003341 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
3342 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08003343 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08003344#endif
3345
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003346 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303347 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003348 {
Priyatharshan P70120512020-09-16 18:47:20 +05303349 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
Lei YU92caa4c2021-02-23 16:59:25 +08003350 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303351 {
3352 return -1;
3353 }
3354 }
Priyatharshan P70120512020-09-16 18:47:20 +05303355 else if (postCompleteConfig.type == ConfigType::DBUS)
3356 {
3357 static sdbusplus::bus::match::match postCompleteEventMonitor =
3358 power_control::postCompleteEventMonitor();
3359 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303360 else
3361 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003362 phosphor::logging::log<phosphor::logging::level::ERR>(
3363 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003364 return -1;
3365 }
3366
3367 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05303368 if (!nmiOutConfig.lineName.empty())
3369 {
3370 setGPIOOutput(nmiOutConfig.lineName, 0, nmiOutLine);
3371 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003372
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003373 // Initialize POWER_OUT and RESET_OUT GPIO.
3374 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05303375 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003376 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07003377 if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
3378 line))
Priyatharshan P70120512020-09-16 18:47:20 +05303379 {
3380 return -1;
3381 }
3382 }
3383 else
3384 {
3385 phosphor::logging::log<phosphor::logging::level::ERR>(
3386 "powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003387 return -1;
3388 }
3389
Priyatharshan P70120512020-09-16 18:47:20 +05303390 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003391 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07003392 if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
3393 line))
Priyatharshan P70120512020-09-16 18:47:20 +05303394 {
3395 return -1;
3396 }
3397 }
3398 else
3399 {
3400 phosphor::logging::log<phosphor::logging::level::ERR>(
3401 "ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003402 return -1;
3403 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003404 // Release line
3405 line.reset();
3406
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003407 // Initialize the power state
Lei YU92caa4c2021-02-23 16:59:25 +08003408 powerState = PowerState::off;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003409 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05303410
3411 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003412 {
Priyatharshan P70120512020-09-16 18:47:20 +05303413 if (psPowerOKLine.get_value() > 0)
3414 {
3415 powerState = PowerState::on;
3416 }
3417 }
3418 else
3419 {
3420 if (getProperty(powerOkConfig))
3421 {
3422 powerState = PowerState::on;
3423 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003424 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003425 // Initialize the power state storage
Lei YU92caa4c2021-02-23 16:59:25 +08003426 if (initializePowerStateStorage() < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003427 {
3428 return -1;
3429 }
3430
3431 // Check if we need to start the Power Restore policy
Lei YU92caa4c2021-02-23 16:59:25 +08003432 powerRestorePolicyCheck();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003433
Lei YU92caa4c2021-02-23 16:59:25 +08003434 if (nmiOutLine)
3435 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003436
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003437 phosphor::logging::log<phosphor::logging::level::INFO>(
3438 "Initializing power state. ");
Lei YU92caa4c2021-02-23 16:59:25 +08003439 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003440
3441 // Power Control Service
3442 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003443 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003444
3445 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303446 hostIface =
3447 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
3448 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003449 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08003450 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003451 "RequestedHostTransition",
3452 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
3453 [](const std::string& requested, std::string& resp) {
3454 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
3455 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003456 // if power button is masked, ignore this
3457 if (!powerButtonMask)
3458 {
3459 sendPowerControlEvent(Event::gracefulPowerOffRequest);
3460 addRestartCause(RestartCause::command);
3461 }
3462 else
3463 {
3464 phosphor::logging::log<phosphor::logging::level::INFO>(
3465 "Power Button Masked.");
3466 throw std::invalid_argument("Transition Request Masked");
3467 return 0;
3468 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003469 }
3470 else if (requested ==
3471 "xyz.openbmc_project.State.Host.Transition.On")
3472 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003473 // if power button is masked, ignore this
3474 if (!powerButtonMask)
3475 {
3476 sendPowerControlEvent(Event::powerOnRequest);
3477 addRestartCause(RestartCause::command);
3478 }
3479 else
3480 {
3481 phosphor::logging::log<phosphor::logging::level::INFO>(
3482 "Power Button Masked.");
3483 throw std::invalid_argument("Transition Request Masked");
3484 return 0;
3485 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003486 }
3487 else if (requested ==
3488 "xyz.openbmc_project.State.Host.Transition.Reboot")
3489 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003490 // if power button is masked, ignore this
3491 if (!powerButtonMask)
3492 {
3493 sendPowerControlEvent(Event::powerCycleRequest);
3494 addRestartCause(RestartCause::command);
3495 }
3496 else
3497 {
3498 phosphor::logging::log<phosphor::logging::level::INFO>(
3499 "Power Button Masked.");
3500 throw std::invalid_argument("Transition Request Masked");
3501 return 0;
3502 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003503 }
3504 else if (requested == "xyz.openbmc_project.State.Host.Transition."
3505 "GracefulWarmReboot")
3506 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003507 // if reset button is masked, ignore this
3508 if (!resetButtonMask)
3509 {
3510 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
3511 addRestartCause(RestartCause::command);
3512 }
3513 else
3514 {
3515 phosphor::logging::log<phosphor::logging::level::INFO>(
3516 "Reset Button Masked.");
3517 throw std::invalid_argument("Transition Request Masked");
3518 return 0;
3519 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003520 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003521 else if (requested == "xyz.openbmc_project.State.Host.Transition."
3522 "ForceWarmReboot")
3523 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003524 // if reset button is masked, ignore this
3525 if (!resetButtonMask)
3526 {
3527 sendPowerControlEvent(Event::resetRequest);
3528 addRestartCause(RestartCause::command);
3529 }
3530 else
3531 {
3532 phosphor::logging::log<phosphor::logging::level::INFO>(
3533 "Reset Button Masked.");
3534 throw std::invalid_argument("Transition Request Masked");
3535 return 0;
3536 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003537 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003538 else
3539 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003540 phosphor::logging::log<phosphor::logging::level::ERR>(
3541 "Unrecognized host state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003542 throw std::invalid_argument("Unrecognized Transition Request");
3543 return 0;
3544 }
3545 resp = requested;
3546 return 1;
3547 });
Lei YU92caa4c2021-02-23 16:59:25 +08003548 hostIface->register_property("CurrentHostState",
3549 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003550
Lei YU92caa4c2021-02-23 16:59:25 +08003551 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003552
3553 // Chassis Control Service
3554 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003555 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003556
3557 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003558 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05303559 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003560 "xyz.openbmc_project.State.Chassis");
3561
Lei YU92caa4c2021-02-23 16:59:25 +08003562 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003563 "RequestedPowerTransition",
3564 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
3565 [](const std::string& requested, std::string& resp) {
3566 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
3567 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003568 // if power button is masked, ignore this
3569 if (!powerButtonMask)
3570 {
3571 sendPowerControlEvent(Event::powerOffRequest);
3572 addRestartCause(RestartCause::command);
3573 }
3574 else
3575 {
3576 phosphor::logging::log<phosphor::logging::level::INFO>(
3577 "Power Button Masked.");
3578 throw std::invalid_argument("Transition Request Masked");
3579 return 0;
3580 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003581 }
3582 else if (requested ==
3583 "xyz.openbmc_project.State.Chassis.Transition.On")
3584 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003585 // if power button is masked, ignore this
3586 if (!powerButtonMask)
3587 {
3588 sendPowerControlEvent(Event::powerOnRequest);
3589 addRestartCause(RestartCause::command);
3590 }
3591 else
3592 {
3593 phosphor::logging::log<phosphor::logging::level::INFO>(
3594 "Power Button Masked.");
3595 throw std::invalid_argument("Transition Request Masked");
3596 return 0;
3597 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003598 }
3599 else if (requested ==
3600 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3601 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003602 // if power button is masked, ignore this
3603 if (!powerButtonMask)
3604 {
3605 sendPowerControlEvent(Event::powerCycleRequest);
3606 addRestartCause(RestartCause::command);
3607 }
3608 else
3609 {
3610 phosphor::logging::log<phosphor::logging::level::INFO>(
3611 "Power Button Masked.");
3612 throw std::invalid_argument("Transition Request Masked");
3613 return 0;
3614 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003615 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003616 else
3617 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003618 phosphor::logging::log<phosphor::logging::level::ERR>(
3619 "Unrecognized chassis state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003620 throw std::invalid_argument("Unrecognized Transition Request");
3621 return 0;
3622 }
3623 resp = requested;
3624 return 1;
3625 });
Lei YU92caa4c2021-02-23 16:59:25 +08003626 chassisIface->register_property("CurrentPowerState",
3627 std::string(getChassisState(powerState)));
3628 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003629
Lei YU92caa4c2021-02-23 16:59:25 +08003630 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003631
Vijay Khemka04175c22020-10-09 14:28:11 -07003632#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003633 // Chassis System Service
3634 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003635 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003636
3637 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003638 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003639 "/xyz/openbmc_project/state/chassis_system0",
3640 "xyz.openbmc_project.State.Chassis");
3641
Lei YU92caa4c2021-02-23 16:59:25 +08003642 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003643 "RequestedPowerTransition",
3644 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3645 [](const std::string& requested, std::string& resp) {
3646 if (requested ==
3647 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3648 {
Lei YU92caa4c2021-02-23 16:59:25 +08003649 systemReset();
3650 addRestartCause(RestartCause::command);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003651 }
3652 else
3653 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003654 phosphor::logging::log<phosphor::logging::level::ERR>(
3655 "Unrecognized chassis system state transition request.");
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003656 throw std::invalid_argument("Unrecognized Transition Request");
3657 return 0;
3658 }
3659 resp = requested;
3660 return 1;
3661 });
Lei YU92caa4c2021-02-23 16:59:25 +08003662 chassisSysIface->register_property(
3663 "CurrentPowerState", std::string(getChassisState(powerState)));
3664 chassisSysIface->register_property("LastStateChangeTime",
3665 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003666
Lei YU92caa4c2021-02-23 16:59:25 +08003667 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003668
Naveen Moses117c34e2021-05-26 20:10:51 +05303669 if (!slotPowerConfig.lineName.empty())
3670 {
3671 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3672 {
3673 return -1;
3674 }
3675
3676 slotPowerState = SlotPowerState::off;
3677 if (slotPowerLine.get_value() > 0)
3678 {
3679 slotPowerState = SlotPowerState::on;
3680 }
3681
3682 chassisSlotIface = chassisSysServer.add_interface(
3683 "/xyz/openbmc_project/state/chassis_system" + node,
3684 "xyz.openbmc_project.State.Chassis");
3685 chassisSlotIface->register_property(
3686 "RequestedPowerTransition",
3687 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3688 [](const std::string& requested, std::string& resp) {
3689 if (requested ==
3690 "xyz.openbmc_project.State.Chassis.Transition.On")
3691 {
3692 slotPowerOn();
3693 }
3694 else if (requested ==
3695 "xyz.openbmc_project.State.Chassis.Transition.Off")
3696 {
3697 slotPowerOff();
3698 }
3699 else if (requested == "xyz.openbmc_project.State.Chassis."
3700 "Transition.PowerCycle")
3701 {
3702 slotPowerCycle();
3703 }
3704 else
3705 {
3706 phosphor::logging::log<phosphor::logging::level::ERR>(
3707 "Unrecognized chassis system state transition "
3708 "request.\n");
3709 throw std::invalid_argument(
3710 "Unrecognized Transition Request");
3711 return 0;
3712 }
3713 resp = requested;
3714 return 1;
3715 });
3716 chassisSlotIface->register_property(
3717 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3718 chassisSlotIface->register_property("LastStateChangeTime",
3719 getCurrentTimeMs());
3720 chassisSlotIface->initialize();
3721 }
3722#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003723 // Buttons Service
3724 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003725 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003726
Priyatharshan P70120512020-09-16 18:47:20 +05303727 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003728 {
Priyatharshan P70120512020-09-16 18:47:20 +05303729 // Power Button Interface
3730 power_control::powerButtonIface = buttonsServer.add_interface(
3731 "/xyz/openbmc_project/chassis/buttons/power",
3732 "xyz.openbmc_project.Chassis.Buttons");
3733
3734 powerButtonIface->register_property(
3735 "ButtonMasked", false, [](const bool requested, bool& current) {
3736 if (requested)
3737 {
3738 if (powerButtonMask)
3739 {
3740 return 1;
3741 }
3742 if (!setGPIOOutput(powerOutConfig.lineName, 1,
3743 powerButtonMask))
3744 {
3745 throw std::runtime_error("Failed to request GPIO");
3746 return 0;
3747 }
3748 phosphor::logging::log<phosphor::logging::level::INFO>(
3749 "Power Button Masked.");
3750 }
3751 else
3752 {
3753 if (!powerButtonMask)
3754 {
3755 return 1;
3756 }
3757 phosphor::logging::log<phosphor::logging::level::INFO>(
3758 "Power Button Un-masked");
3759 powerButtonMask.reset();
3760 }
3761 // Update the mask setting
3762 current = requested;
3763 return 1;
3764 });
3765
3766 // Check power button state
3767 bool powerButtonPressed;
3768 if (powerButtonConfig.type == ConfigType::GPIO)
3769 {
3770 powerButtonPressed = powerButtonLine.get_value() == 0;
3771 }
3772 else
3773 {
3774 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3775 }
3776
3777 powerButtonIface->register_property("ButtonPressed",
3778 powerButtonPressed);
3779
3780 powerButtonIface->initialize();
3781 }
3782
3783 if (!resetButtonConfig.lineName.empty())
3784 {
3785 // Reset Button Interface
3786
Lei YU92caa4c2021-02-23 16:59:25 +08003787 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003788 "/xyz/openbmc_project/chassis/buttons/reset",
3789 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003790
Lei YU92caa4c2021-02-23 16:59:25 +08003791 resetButtonIface->register_property(
John Wang6c090072020-09-30 13:32:16 +08003792 "ButtonMasked", false, [](const bool requested, bool& current) {
3793 if (requested)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003794 {
Lei YU92caa4c2021-02-23 16:59:25 +08003795 if (resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003796 {
3797 return 1;
3798 }
Priyatharshan P70120512020-09-16 18:47:20 +05303799 if (!setGPIOOutput(resetOutConfig.lineName, 1,
3800 resetButtonMask))
John Wang6c090072020-09-30 13:32:16 +08003801 {
3802 throw std::runtime_error("Failed to request GPIO");
3803 return 0;
3804 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003805 phosphor::logging::log<phosphor::logging::level::INFO>(
3806 "Reset Button Masked.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003807 }
John Wang6c090072020-09-30 13:32:16 +08003808 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003809 {
Lei YU92caa4c2021-02-23 16:59:25 +08003810 if (!resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003811 {
3812 return 1;
3813 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003814 phosphor::logging::log<phosphor::logging::level::INFO>(
3815 "Reset Button Un-masked");
Lei YU92caa4c2021-02-23 16:59:25 +08003816 resetButtonMask.reset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003817 }
John Wang6c090072020-09-30 13:32:16 +08003818 // Update the mask setting
3819 current = requested;
3820 return 1;
3821 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003822
John Wang6c090072020-09-30 13:32:16 +08003823 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303824 bool resetButtonPressed;
3825 if (resetButtonConfig.type == ConfigType::GPIO)
3826 {
3827 resetButtonPressed = resetButtonLine.get_value() == 0;
3828 }
3829 else
3830 {
3831 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3832 }
3833
Lei YU92caa4c2021-02-23 16:59:25 +08003834 resetButtonIface->register_property("ButtonPressed",
3835 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003836
Lei YU92caa4c2021-02-23 16:59:25 +08003837 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003838 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003839
Lei YU92caa4c2021-02-23 16:59:25 +08003840 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003841 {
3842 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003843 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003844 "/xyz/openbmc_project/chassis/buttons/nmi",
3845 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003846
Lei YU92caa4c2021-02-23 16:59:25 +08003847 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003848 "ButtonMasked", false, [](const bool requested, bool& current) {
Lei YU92caa4c2021-02-23 16:59:25 +08003849 if (nmiButtonMasked == requested)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003850 {
3851 // NMI button mask is already set as requested, so no change
3852 return 1;
3853 }
3854 if (requested)
3855 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003856 phosphor::logging::log<phosphor::logging::level::INFO>(
3857 "NMI Button Masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003858 nmiButtonMasked = true;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003859 }
3860 else
3861 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003862 phosphor::logging::log<phosphor::logging::level::INFO>(
3863 "NMI Button Un-masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003864 nmiButtonMasked = false;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003865 }
3866 // Update the mask setting
Lei YU92caa4c2021-02-23 16:59:25 +08003867 current = nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003868 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003869 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003870
Vijay Khemka33a532d2019-11-14 16:50:35 -08003871 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303872 bool nmiButtonPressed;
3873 if (nmiButtonConfig.type == ConfigType::GPIO)
3874 {
3875 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3876 }
3877 else
3878 {
3879 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3880 }
3881
Lei YU92caa4c2021-02-23 16:59:25 +08003882 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003883
Lei YU92caa4c2021-02-23 16:59:25 +08003884 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003885 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003886
Lei YU92caa4c2021-02-23 16:59:25 +08003887 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003888 {
3889 // NMI out Service
3890 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003891 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003892
Vijay Khemka33a532d2019-11-14 16:50:35 -08003893 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303894 nmiOutIface = nmiOutServer.add_interface(
3895 "/xyz/openbmc_project/control/host" + node + "/nmi",
3896 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003897 nmiOutIface->register_method("NMI", nmiReset);
3898 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003899 }
Chen Yugang174ec662019-08-19 19:58:49 +08003900
Lei YU92caa4c2021-02-23 16:59:25 +08003901 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003902 {
3903 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003904 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003905 "/xyz/openbmc_project/chassis/buttons/id",
3906 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003907
Vijay Khemka33a532d2019-11-14 16:50:35 -08003908 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303909 bool idButtonPressed;
3910 if (idButtonConfig.type == ConfigType::GPIO)
3911 {
3912 idButtonPressed = idButtonLine.get_value() == 0;
3913 }
3914 else
3915 {
3916 idButtonPressed = getProperty(idButtonConfig) == 0;
3917 }
3918
Lei YU92caa4c2021-02-23 16:59:25 +08003919 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003920
Lei YU92caa4c2021-02-23 16:59:25 +08003921 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003922 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003923
3924 // OS State Service
3925 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003926 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003927
3928 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003929 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003930 "/xyz/openbmc_project/state/os",
3931 "xyz.openbmc_project.State.OperatingSystem.Status");
3932
3933 // Get the initial OS state based on POST complete
3934 // 0: Asserted, OS state is "Standby" (ready to boot)
3935 // 1: De-Asserted, OS state is "Inactive"
Priyatharshan P70120512020-09-16 18:47:20 +05303936 std::string osState;
3937 if (postCompleteConfig.type == ConfigType::GPIO)
3938 {
3939 osState = postCompleteLine.get_value() > 0 ? "Inactive" : "Standby";
3940 }
3941 else
3942 {
3943 osState = getProperty(postCompleteConfig) > 0 ? "Inactive" : "Standby";
3944 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003945
Lei YU92caa4c2021-02-23 16:59:25 +08003946 osIface->register_property("OperatingSystemState", std::string(osState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003947
Lei YU92caa4c2021-02-23 16:59:25 +08003948 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003949
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003950 // Restart Cause Service
3951 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003952 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003953
3954 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003955 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303956 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003957 "xyz.openbmc_project.Control.Host.RestartCause");
3958
Lei YU92caa4c2021-02-23 16:59:25 +08003959 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003960 "RestartCause",
3961 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3962
Lei YU92caa4c2021-02-23 16:59:25 +08003963 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003964 "RequestedRestartCause",
3965 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3966 [](const std::string& requested, std::string& resp) {
3967 if (requested ==
3968 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3969 {
Lei YU92caa4c2021-02-23 16:59:25 +08003970 addRestartCause(RestartCause::watchdog);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003971 }
3972 else
3973 {
3974 throw std::invalid_argument(
3975 "Unrecognized RestartCause Request");
3976 return 0;
3977 }
3978
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003979 std::string logMsg = "RestartCause requested: " + requested;
3980 phosphor::logging::log<phosphor::logging::level::INFO>(
3981 logMsg.c_str());
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003982 resp = requested;
3983 return 1;
3984 });
3985
Lei YU92caa4c2021-02-23 16:59:25 +08003986 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003987
Lei YU92caa4c2021-02-23 16:59:25 +08003988 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003989
Lei YU92caa4c2021-02-23 16:59:25 +08003990 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003991
3992 return 0;
3993}