blob: 47bdd043074670870a39048fe06247ed77450af2 [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;
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001209
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001210 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001211 gpioAssertTimer.async_wait([gpioLine, polarizedvalue,
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001212 name](const boost::system::error_code ec) {
1213 // Set the GPIO line back to the opposite value
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001214 gpioLine.set_value(!polarizedvalue);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001215 std::string logMsg = name + " released";
1216 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
1217 if (ec)
1218 {
1219 // operation_aborted is expected if timer is canceled before
1220 // completion.
1221 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001222 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001223 std::string errMsg =
1224 name + " async_wait failed: " + ec.message();
1225 phosphor::logging::log<phosphor::logging::level::ERR>(
1226 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001227 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001228 }
1229 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001230 return 0;
1231}
1232
1233static void powerOn()
1234{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001235 setGPIOOutputForMs(powerOutConfig, 0, TimerMap["powerPulseTimeMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001236}
Naveen Moses117c34e2021-05-26 20:10:51 +05301237#ifdef CHASSIS_SYSTEM_RESET
1238static int slotPowerOn()
1239{
1240 if (power_control::slotPowerState != power_control::SlotPowerState::on)
1241 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001242
Naveen Moses117c34e2021-05-26 20:10:51 +05301243 slotPowerLine.set_value(1);
1244
1245 if (slotPowerLine.get_value() > 0)
1246 {
1247 setSlotPowerState(SlotPowerState::on);
1248 phosphor::logging::log<phosphor::logging::level::INFO>(
1249 "Slot Power is switched On\n");
1250 }
1251 else
1252 {
1253 return -1;
1254 }
1255 }
1256 else
1257 {
1258 phosphor::logging::log<phosphor::logging::level::INFO>(
1259 "Slot Power is already in 'On' state\n");
1260 return -1;
1261 }
1262 return 0;
1263}
1264static int slotPowerOff()
1265{
1266 if (power_control::slotPowerState != power_control::SlotPowerState::off)
1267 {
1268 slotPowerLine.set_value(0);
1269
1270 if (!(slotPowerLine.get_value() > 0))
1271 {
1272 setSlotPowerState(SlotPowerState::off);
1273 setPowerState(PowerState::off);
1274 phosphor::logging::log<phosphor::logging::level::INFO>(
1275 "Slot Power is switched Off\n");
1276 }
1277 else
1278 {
1279 return -1;
1280 }
1281 }
1282 else
1283 {
1284 phosphor::logging::log<phosphor::logging::level::INFO>(
1285 "Slot Power is already in 'Off' state\n");
1286 return -1;
1287 }
1288 return 0;
1289}
1290static void slotPowerCycle()
1291{
1292 phosphor::logging::log<phosphor::logging::level::INFO>(
1293 "Slot Power Cycle started\n");
1294 slotPowerOff();
1295 slotPowerCycleTimer.expires_after(
1296 std::chrono::milliseconds(TimerMap["slotPowerCycleTimeMs"]));
1297 slotPowerCycleTimer.async_wait([](const boost::system::error_code ec) {
1298 if (ec)
1299 {
1300 if (ec != boost::asio::error::operation_aborted)
1301 {
1302 std::string errMsg =
1303 "Slot Power cycle timer async_wait failed: " + ec.message();
1304 phosphor::logging::log<phosphor::logging::level::ERR>(
1305 errMsg.c_str());
1306 }
1307 phosphor::logging::log<phosphor::logging::level::INFO>(
1308 "Slot Power cycle timer canceled\n");
1309 return;
1310 }
1311 phosphor::logging::log<phosphor::logging::level::INFO>(
1312 "Slot Power cycle timer completed\n");
1313 slotPowerOn();
1314 phosphor::logging::log<phosphor::logging::level::INFO>(
1315 "Slot Power Cycle Completed\n");
1316 });
1317}
1318#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001319static void gracefulPowerOff()
1320{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001321 setGPIOOutputForMs(powerOutConfig, 0, TimerMap["powerPulseTimeMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001322}
1323
1324static void forcePowerOff()
1325{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001326 if (setGPIOOutputForMs(powerOutConfig, 0, TimerMap["forceOffPulseTimeMs"]) <
1327 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001328 {
1329 return;
1330 }
1331
1332 // If the force off timer expires, then the PCH power-button override
1333 // failed, so attempt the Unconditional Powerdown SMBus command.
1334 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1335 if (ec)
1336 {
1337 // operation_aborted is expected if timer is canceled before
1338 // completion.
1339 if (ec != boost::asio::error::operation_aborted)
1340 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001341 std::string errMsg =
1342 "Force power off async_wait failed: " + ec.message();
1343 phosphor::logging::log<phosphor::logging::level::ERR>(
1344 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001345 }
1346 return;
1347 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001348
1349 phosphor::logging::log<phosphor::logging::level::INFO>(
1350 "PCH Power-button override failed. Issuing Unconditional Powerdown "
1351 "SMBus command.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001352 const static constexpr size_t pchDevBusAddress = 3;
1353 const static constexpr size_t pchDevSlaveAddress = 0x44;
1354 const static constexpr size_t pchCmdReg = 0;
1355 const static constexpr size_t pchPowerDownCmd = 0x02;
1356 if (i2cSet(pchDevBusAddress, pchDevSlaveAddress, pchCmdReg,
1357 pchPowerDownCmd) < 0)
1358 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001359 phosphor::logging::log<phosphor::logging::level::ERR>(
1360 "Unconditional Powerdown command failed! Not sure what to do "
1361 "now.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001362 }
1363 });
1364}
1365
1366static void reset()
1367{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001368 setGPIOOutputForMs(resetOutConfig, 0, TimerMap["resetPulseTimeMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001369}
1370
1371static void gracefulPowerOffTimerStart()
1372{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001373 phosphor::logging::log<phosphor::logging::level::INFO>(
1374 "Graceful power-off timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001375 gracefulPowerOffTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301376 std::chrono::seconds(TimerMap["gracefulPowerOffTimeS"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001377 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1378 if (ec)
1379 {
1380 // operation_aborted is expected if timer is canceled before
1381 // completion.
1382 if (ec != boost::asio::error::operation_aborted)
1383 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001384 std::string errMsg =
1385 "Graceful power-off async_wait failed: " + ec.message();
1386 phosphor::logging::log<phosphor::logging::level::ERR>(
1387 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001388 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001389 phosphor::logging::log<phosphor::logging::level::INFO>(
1390 "Graceful power-off timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001391 return;
1392 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001393 phosphor::logging::log<phosphor::logging::level::INFO>(
1394 "Graceful power-off timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001395 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1396 });
1397}
1398
1399static void powerCycleTimerStart()
1400{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001401 phosphor::logging::log<phosphor::logging::level::INFO>(
1402 "Power-cycle timer started");
Priyatharshan P70120512020-09-16 18:47:20 +05301403 powerCycleTimer.expires_after(
1404 std::chrono::milliseconds(TimerMap["powerCycleTimeMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001405 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1406 if (ec)
1407 {
1408 // operation_aborted is expected if timer is canceled before
1409 // completion.
1410 if (ec != boost::asio::error::operation_aborted)
1411 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001412 std::string errMsg =
1413 "Power-cycle async_wait failed: " + ec.message();
1414 phosphor::logging::log<phosphor::logging::level::ERR>(
1415 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001416 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001417 phosphor::logging::log<phosphor::logging::level::INFO>(
1418 "Power-cycle timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001419 return;
1420 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001421 phosphor::logging::log<phosphor::logging::level::INFO>(
1422 "Power-cycle timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001423 sendPowerControlEvent(Event::powerCycleTimerExpired);
1424 });
1425}
1426
1427static void psPowerOKWatchdogTimerStart()
1428{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001429 phosphor::logging::log<phosphor::logging::level::INFO>(
1430 "power supply power OK watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001431 psPowerOKWatchdogTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301432 std::chrono::milliseconds(TimerMap["psPowerOKWatchdogTimeMs"]));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001433 psPowerOKWatchdogTimer.async_wait([](const boost::system::error_code ec) {
1434 if (ec)
1435 {
1436 // operation_aborted is expected if timer is canceled before
1437 // completion.
1438 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001439 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001440 std::string errMsg =
1441 "power supply power OK watchdog async_wait failed: " +
1442 ec.message();
1443 phosphor::logging::log<phosphor::logging::level::ERR>(
1444 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001445 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001446 phosphor::logging::log<phosphor::logging::level::INFO>(
1447 "power supply power OK watchdog timer canceled");
1448 return;
1449 }
1450 phosphor::logging::log<phosphor::logging::level::INFO>(
1451 "power supply power OK watchdog timer expired");
1452 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1453 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001454}
1455
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001456static void warmResetCheckTimerStart()
1457{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001458 phosphor::logging::log<phosphor::logging::level::INFO>(
1459 "Warm reset check timer started");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001460 warmResetCheckTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301461 std::chrono::milliseconds(TimerMap["warmResetCheckTimeMs"]));
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001462 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1463 if (ec)
1464 {
1465 // operation_aborted is expected if timer is canceled before
1466 // completion.
1467 if (ec != boost::asio::error::operation_aborted)
1468 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001469 std::string errMsg =
1470 "Warm reset check async_wait failed: " + ec.message();
1471 phosphor::logging::log<phosphor::logging::level::ERR>(
1472 errMsg.c_str());
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001473 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001474 phosphor::logging::log<phosphor::logging::level::INFO>(
1475 "Warm reset check timer canceled");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001476 return;
1477 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001478 phosphor::logging::log<phosphor::logging::level::INFO>(
1479 "Warm reset check timer completed");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001480 sendPowerControlEvent(Event::warmResetDetected);
1481 });
1482}
1483
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001484static void pohCounterTimerStart()
1485{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001486 phosphor::logging::log<phosphor::logging::level::INFO>("POH timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001487 // Set the time-out as 1 hour, to align with POH command in ipmid
1488 pohCounterTimer.expires_after(std::chrono::hours(1));
1489 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1490 if (ec)
1491 {
1492 // operation_aborted is expected if timer is canceled before
1493 // completion.
1494 if (ec != boost::asio::error::operation_aborted)
1495 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001496 std::string errMsg =
1497 "POH timer async_wait failed: " + ec.message();
1498 phosphor::logging::log<phosphor::logging::level::ERR>(
1499 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001500 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001501 phosphor::logging::log<phosphor::logging::level::INFO>(
1502 "POH timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001503 return;
1504 }
1505
1506 if (getHostState(powerState) !=
1507 "xyz.openbmc_project.State.Host.HostState.Running")
1508 {
1509 return;
1510 }
1511
1512 conn->async_method_call(
1513 [](boost::system::error_code ec,
1514 const std::variant<uint32_t>& pohCounterProperty) {
1515 if (ec)
1516 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001517 phosphor::logging::log<phosphor::logging::level::INFO>(
1518 "error to get poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001519 return;
1520 }
1521 const uint32_t* pohCounter =
1522 std::get_if<uint32_t>(&pohCounterProperty);
1523 if (pohCounter == nullptr)
1524 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001525 phosphor::logging::log<phosphor::logging::level::INFO>(
1526 "unable to read poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001527 return;
1528 }
1529
1530 conn->async_method_call(
1531 [](boost::system::error_code ec) {
1532 if (ec)
1533 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001534 phosphor::logging::log<
1535 phosphor::logging::level::INFO>(
1536 "failed to set poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001537 }
1538 },
1539 "xyz.openbmc_project.Settings",
1540 "/xyz/openbmc_project/state/chassis0",
1541 "org.freedesktop.DBus.Properties", "Set",
1542 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1543 std::variant<uint32_t>(*pohCounter + 1));
1544 },
1545 "xyz.openbmc_project.Settings",
1546 "/xyz/openbmc_project/state/chassis0",
1547 "org.freedesktop.DBus.Properties", "Get",
1548 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1549
1550 pohCounterTimerStart();
1551 });
1552}
1553
1554static void currentHostStateMonitor()
1555{
Yong Li8d660212019-12-27 10:18:10 +08001556 if (getHostState(powerState) ==
1557 "xyz.openbmc_project.State.Host.HostState.Running")
1558 {
1559 pohCounterTimerStart();
1560 // Clear the restart cause set for the next restart
1561 clearRestartCause();
1562 }
1563 else
1564 {
1565 pohCounterTimer.cancel();
1566 // Set the restart cause set for this restart
1567 setRestartCause();
1568 }
1569
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001570 static auto match = sdbusplus::bus::match::match(
1571 *conn,
1572 "type='signal',member='PropertiesChanged', "
1573 "interface='org.freedesktop.DBus.Properties', "
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001574 "arg0='xyz.openbmc_project.State.Host'",
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001575 [](sdbusplus::message::message& message) {
1576 std::string intfName;
1577 std::map<std::string, std::variant<std::string>> properties;
1578
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001579 try
1580 {
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001581 message.read(intfName, properties);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001582 }
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001583 catch (std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001584 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001585 phosphor::logging::log<phosphor::logging::level::ERR>(
1586 "Unable to read host state");
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001587 return;
1588 }
1589 if (properties.empty())
1590 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001591 phosphor::logging::log<phosphor::logging::level::ERR>(
1592 "ERROR: Empty PropertiesChanged signal received");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001593 return;
1594 }
1595
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001596 // We only want to check for CurrentHostState
1597 if (properties.begin()->first != "CurrentHostState")
1598 {
1599 return;
1600 }
1601 std::string* currentHostState =
1602 std::get_if<std::string>(&(properties.begin()->second));
1603 if (currentHostState == nullptr)
1604 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001605 std::string errMsg =
1606 properties.begin()->first + " property invalid";
1607 phosphor::logging::log<phosphor::logging::level::ERR>(
1608 errMsg.c_str());
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001609 return;
1610 }
1611
1612 if (*currentHostState ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001613 "xyz.openbmc_project.State.Host.HostState.Running")
1614 {
1615 pohCounterTimerStart();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001616 // Clear the restart cause set for the next restart
1617 clearRestartCause();
Yong Li8d660212019-12-27 10:18:10 +08001618 sd_journal_send("MESSAGE=Host system DC power is on",
1619 "PRIORITY=%i", LOG_INFO,
1620 "REDFISH_MESSAGE_ID=%s",
1621 "OpenBMC.0.1.DCPowerOn", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001622 }
1623 else
1624 {
1625 pohCounterTimer.cancel();
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301626 // POST_COMPLETE GPIO event is not working in some platforms
1627 // when power state is changed to OFF. This resulted in
1628 // 'OperatingSystemState' to stay at 'Standby', even though
1629 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1630 // if HostState is trurned to OFF.
1631 osIface->set_property("OperatingSystemState",
1632 std::string("Inactive"));
1633
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001634 // Set the restart cause set for this restart
1635 setRestartCause();
Rashmi RV89f61312020-01-22 15:41:50 +05301636 resetACBootProperty();
Yong Li8d660212019-12-27 10:18:10 +08001637 sd_journal_send("MESSAGE=Host system DC power is off",
1638 "PRIORITY=%i", LOG_INFO,
1639 "REDFISH_MESSAGE_ID=%s",
1640 "OpenBMC.0.1.DCPowerOff", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001641 }
1642 });
1643}
1644
1645static void sioPowerGoodWatchdogTimerStart()
1646{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001647 phosphor::logging::log<phosphor::logging::level::INFO>(
1648 "SIO power good watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001649 sioPowerGoodWatchdogTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301650 std::chrono::milliseconds(TimerMap["sioPowerGoodWatchdogTimeMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001651 sioPowerGoodWatchdogTimer.async_wait(
1652 [](const boost::system::error_code ec) {
1653 if (ec)
1654 {
1655 // operation_aborted is expected if timer is canceled before
1656 // completion.
1657 if (ec != boost::asio::error::operation_aborted)
1658 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001659 std::string errMsg =
1660 "SIO power good watchdog async_wait failed: " +
1661 ec.message();
1662 phosphor::logging::log<phosphor::logging::level::ERR>(
1663 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001664 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001665 phosphor::logging::log<phosphor::logging::level::INFO>(
1666 "SIO power good watchdog timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001667 return;
1668 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001669 phosphor::logging::log<phosphor::logging::level::INFO>(
1670 "SIO power good watchdog timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001671 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1672 });
1673}
1674
1675static void powerStateOn(const Event event)
1676{
1677 logEvent(__FUNCTION__, event);
1678 switch (event)
1679 {
1680 case Event::psPowerOKDeAssert:
1681 setPowerState(PowerState::off);
1682 // DC power is unexpectedly lost, beep
1683 beep(beepPowerFail);
1684 break;
1685 case Event::sioS5Assert:
1686 setPowerState(PowerState::transitionToOff);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001687 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001688 break;
Jason M. Billsfb957332021-01-28 13:18:46 -08001689#if USE_PLT_RST
1690 case Event::pltRstAssert:
1691#else
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001692 case Event::postCompleteDeAssert:
Jason M. Billsfb957332021-01-28 13:18:46 -08001693#endif
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001694 setPowerState(PowerState::checkForWarmReset);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001695 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001696 warmResetCheckTimerStart();
1697 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001698 case Event::powerButtonPressed:
1699 setPowerState(PowerState::gracefulTransitionToOff);
1700 gracefulPowerOffTimerStart();
1701 break;
1702 case Event::powerOffRequest:
1703 setPowerState(PowerState::transitionToOff);
1704 forcePowerOff();
1705 break;
1706 case Event::gracefulPowerOffRequest:
1707 setPowerState(PowerState::gracefulTransitionToOff);
1708 gracefulPowerOffTimerStart();
1709 gracefulPowerOff();
1710 break;
1711 case Event::powerCycleRequest:
1712 setPowerState(PowerState::transitionToCycleOff);
1713 forcePowerOff();
1714 break;
1715 case Event::gracefulPowerCycleRequest:
1716 setPowerState(PowerState::gracefulTransitionToCycleOff);
1717 gracefulPowerOffTimerStart();
1718 gracefulPowerOff();
1719 break;
1720 case Event::resetRequest:
1721 reset();
1722 break;
1723 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001724 phosphor::logging::log<phosphor::logging::level::INFO>(
1725 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001726 break;
1727 }
1728}
1729
1730static void powerStateWaitForPSPowerOK(const Event event)
1731{
1732 logEvent(__FUNCTION__, event);
1733 switch (event)
1734 {
1735 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301736 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001737 // Cancel any GPIO assertions held during the transition
1738 gpioAssertTimer.cancel();
1739 psPowerOKWatchdogTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301740 if (sioEnabled == true)
1741 {
1742 sioPowerGoodWatchdogTimerStart();
1743 setPowerState(PowerState::waitForSIOPowerGood);
1744 }
1745 else
1746 {
1747 setPowerState(PowerState::on);
1748 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001749 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301750 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001751 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001752 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001753 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001754 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001755 case Event::sioPowerGoodAssert:
1756 psPowerOKWatchdogTimer.cancel();
1757 setPowerState(PowerState::on);
1758 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001759 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001760 phosphor::logging::log<phosphor::logging::level::INFO>(
1761 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001762 break;
1763 }
1764}
1765
1766static void powerStateWaitForSIOPowerGood(const Event event)
1767{
1768 logEvent(__FUNCTION__, event);
1769 switch (event)
1770 {
1771 case Event::sioPowerGoodAssert:
1772 sioPowerGoodWatchdogTimer.cancel();
1773 setPowerState(PowerState::on);
1774 break;
1775 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001776 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001777 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001778 break;
1779 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001780 phosphor::logging::log<phosphor::logging::level::INFO>(
1781 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001782 break;
1783 }
1784}
1785
1786static void powerStateOff(const Event event)
1787{
1788 logEvent(__FUNCTION__, event);
1789 switch (event)
1790 {
1791 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301792 {
1793 if (sioEnabled == true)
1794 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001795 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301796 setPowerState(PowerState::waitForSIOPowerGood);
1797 }
1798 else
1799 {
1800 setPowerState(PowerState::on);
1801 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001802 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301803 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001804 case Event::sioS5DeAssert:
1805 setPowerState(PowerState::waitForPSPowerOK);
1806 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001807 case Event::sioPowerGoodAssert:
1808 setPowerState(PowerState::on);
1809 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001810 case Event::powerButtonPressed:
1811 psPowerOKWatchdogTimerStart();
1812 setPowerState(PowerState::waitForPSPowerOK);
1813 break;
1814 case Event::powerOnRequest:
1815 psPowerOKWatchdogTimerStart();
1816 setPowerState(PowerState::waitForPSPowerOK);
1817 powerOn();
1818 break;
1819 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001820 phosphor::logging::log<phosphor::logging::level::INFO>(
1821 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001822 break;
1823 }
1824}
1825
1826static void powerStateTransitionToOff(const Event event)
1827{
1828 logEvent(__FUNCTION__, event);
1829 switch (event)
1830 {
1831 case Event::psPowerOKDeAssert:
1832 // Cancel any GPIO assertions held during the transition
1833 gpioAssertTimer.cancel();
1834 setPowerState(PowerState::off);
1835 break;
1836 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001837 phosphor::logging::log<phosphor::logging::level::INFO>(
1838 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001839 break;
1840 }
1841}
1842
1843static void powerStateGracefulTransitionToOff(const Event event)
1844{
1845 logEvent(__FUNCTION__, event);
1846 switch (event)
1847 {
1848 case Event::psPowerOKDeAssert:
1849 gracefulPowerOffTimer.cancel();
1850 setPowerState(PowerState::off);
1851 break;
1852 case Event::gracefulPowerOffTimerExpired:
1853 setPowerState(PowerState::on);
1854 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001855 case Event::powerOffRequest:
1856 gracefulPowerOffTimer.cancel();
1857 setPowerState(PowerState::transitionToOff);
1858 forcePowerOff();
1859 break;
1860 case Event::powerCycleRequest:
1861 gracefulPowerOffTimer.cancel();
1862 setPowerState(PowerState::transitionToCycleOff);
1863 forcePowerOff();
1864 break;
1865 case Event::resetRequest:
1866 gracefulPowerOffTimer.cancel();
1867 setPowerState(PowerState::on);
1868 reset();
1869 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001870 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001871 phosphor::logging::log<phosphor::logging::level::INFO>(
1872 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001873 break;
1874 }
1875}
1876
1877static void powerStateCycleOff(const Event event)
1878{
1879 logEvent(__FUNCTION__, event);
1880 switch (event)
1881 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001882 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301883 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001884 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301885 if (sioEnabled == true)
1886 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001887 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301888 setPowerState(PowerState::waitForSIOPowerGood);
1889 }
1890 else
1891 {
1892 setPowerState(PowerState::on);
1893 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001894 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301895 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001896 case Event::sioS5DeAssert:
1897 powerCycleTimer.cancel();
1898 setPowerState(PowerState::waitForPSPowerOK);
1899 break;
1900 case Event::powerButtonPressed:
1901 powerCycleTimer.cancel();
1902 psPowerOKWatchdogTimerStart();
1903 setPowerState(PowerState::waitForPSPowerOK);
1904 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001905 case Event::powerCycleTimerExpired:
1906 psPowerOKWatchdogTimerStart();
1907 setPowerState(PowerState::waitForPSPowerOK);
1908 powerOn();
1909 break;
1910 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001911 phosphor::logging::log<phosphor::logging::level::INFO>(
1912 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001913 break;
1914 }
1915}
1916
1917static void powerStateTransitionToCycleOff(const Event event)
1918{
1919 logEvent(__FUNCTION__, event);
1920 switch (event)
1921 {
1922 case Event::psPowerOKDeAssert:
1923 // Cancel any GPIO assertions held during the transition
1924 gpioAssertTimer.cancel();
1925 setPowerState(PowerState::cycleOff);
1926 powerCycleTimerStart();
1927 break;
1928 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001929 phosphor::logging::log<phosphor::logging::level::INFO>(
1930 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001931 break;
1932 }
1933}
1934
1935static void powerStateGracefulTransitionToCycleOff(const Event event)
1936{
1937 logEvent(__FUNCTION__, event);
1938 switch (event)
1939 {
1940 case Event::psPowerOKDeAssert:
1941 gracefulPowerOffTimer.cancel();
1942 setPowerState(PowerState::cycleOff);
1943 powerCycleTimerStart();
1944 break;
1945 case Event::gracefulPowerOffTimerExpired:
1946 setPowerState(PowerState::on);
1947 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001948 case Event::powerOffRequest:
1949 gracefulPowerOffTimer.cancel();
1950 setPowerState(PowerState::transitionToOff);
1951 forcePowerOff();
1952 break;
1953 case Event::powerCycleRequest:
1954 gracefulPowerOffTimer.cancel();
1955 setPowerState(PowerState::transitionToCycleOff);
1956 forcePowerOff();
1957 break;
1958 case Event::resetRequest:
1959 gracefulPowerOffTimer.cancel();
1960 setPowerState(PowerState::on);
1961 reset();
1962 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001963 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001964 phosphor::logging::log<phosphor::logging::level::INFO>(
1965 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001966 break;
1967 }
1968}
1969
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001970static void powerStateCheckForWarmReset(const Event event)
1971{
1972 logEvent(__FUNCTION__, event);
1973 switch (event)
1974 {
1975 case Event::sioS5Assert:
1976 warmResetCheckTimer.cancel();
1977 setPowerState(PowerState::transitionToOff);
1978 break;
1979 case Event::warmResetDetected:
1980 setPowerState(PowerState::on);
1981 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001982 case Event::psPowerOKDeAssert:
1983 warmResetCheckTimer.cancel();
1984 setPowerState(PowerState::off);
1985 // DC power is unexpectedly lost, beep
1986 beep(beepPowerFail);
1987 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001988 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001989 phosphor::logging::log<phosphor::logging::level::INFO>(
1990 "No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001991 break;
1992 }
1993}
1994
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001995static void psPowerOKHandler()
1996{
1997 gpiod::line_event gpioLineEvent = psPowerOKLine.event_read();
1998
1999 Event powerControlEvent =
2000 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
2001 ? Event::psPowerOKAssert
2002 : Event::psPowerOKDeAssert;
2003
2004 sendPowerControlEvent(powerControlEvent);
2005 psPowerOKEvent.async_wait(
2006 boost::asio::posix::stream_descriptor::wait_read,
2007 [](const boost::system::error_code ec) {
2008 if (ec)
2009 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002010 std::string errMsg =
2011 "power supply power OK handler error: " + ec.message();
2012 phosphor::logging::log<phosphor::logging::level::ERR>(
2013 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002014 return;
2015 }
2016 psPowerOKHandler();
2017 });
2018}
2019
2020static void sioPowerGoodHandler()
2021{
2022 gpiod::line_event gpioLineEvent = sioPowerGoodLine.event_read();
2023
2024 Event powerControlEvent =
2025 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
2026 ? Event::sioPowerGoodAssert
2027 : Event::sioPowerGoodDeAssert;
2028
2029 sendPowerControlEvent(powerControlEvent);
2030 sioPowerGoodEvent.async_wait(
2031 boost::asio::posix::stream_descriptor::wait_read,
2032 [](const boost::system::error_code ec) {
2033 if (ec)
2034 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002035 std::string errMsg =
2036 "SIO power good handler error: " + ec.message();
2037 phosphor::logging::log<phosphor::logging::level::ERR>(
2038 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002039 return;
2040 }
2041 sioPowerGoodHandler();
2042 });
2043}
2044
2045static void sioOnControlHandler()
2046{
2047 gpiod::line_event gpioLineEvent = sioOnControlLine.event_read();
2048
2049 bool sioOnControl =
2050 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE;
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002051 std::string logMsg =
2052 "SIO_ONCONTROL value changed: " + std::to_string(sioOnControl);
2053 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002054 sioOnControlEvent.async_wait(
2055 boost::asio::posix::stream_descriptor::wait_read,
2056 [](const boost::system::error_code ec) {
2057 if (ec)
2058 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002059 std::string errMsg =
2060 "SIO ONCONTROL handler error: " + ec.message();
2061 phosphor::logging::log<phosphor::logging::level::ERR>(
2062 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002063 return;
2064 }
2065 sioOnControlHandler();
2066 });
2067}
2068
2069static void sioS5Handler()
2070{
2071 gpiod::line_event gpioLineEvent = sioS5Line.event_read();
2072
2073 Event powerControlEvent =
2074 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE
2075 ? Event::sioS5Assert
2076 : Event::sioS5DeAssert;
2077
2078 sendPowerControlEvent(powerControlEvent);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002079 sioS5Event.async_wait(
2080 boost::asio::posix::stream_descriptor::wait_read,
2081 [](const boost::system::error_code ec) {
2082 if (ec)
2083 {
2084 std::string errMsg = "SIO S5 handler error: " + ec.message();
2085 phosphor::logging::log<phosphor::logging::level::ERR>(
2086 errMsg.c_str());
2087 return;
2088 }
2089 sioS5Handler();
2090 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002091}
2092
2093static void powerButtonHandler()
2094{
2095 gpiod::line_event gpioLineEvent = powerButtonLine.event_read();
2096
2097 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2098 {
2099 powerButtonPressLog();
2100 powerButtonIface->set_property("ButtonPressed", true);
2101 if (!powerButtonMask)
2102 {
2103 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002104 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002105 }
2106 else
2107 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002108 phosphor::logging::log<phosphor::logging::level::INFO>(
2109 "power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002110 }
2111 }
2112 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2113 {
2114 powerButtonIface->set_property("ButtonPressed", false);
2115 }
2116 powerButtonEvent.async_wait(
2117 boost::asio::posix::stream_descriptor::wait_read,
2118 [](const boost::system::error_code ec) {
2119 if (ec)
2120 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002121 std::string errMsg =
2122 "power button handler error: " + ec.message();
2123 phosphor::logging::log<phosphor::logging::level::ERR>(
2124 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002125 return;
2126 }
2127 powerButtonHandler();
2128 });
2129}
2130
2131static void resetButtonHandler()
2132{
2133 gpiod::line_event gpioLineEvent = resetButtonLine.event_read();
2134
2135 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2136 {
2137 resetButtonPressLog();
2138 resetButtonIface->set_property("ButtonPressed", true);
2139 if (!resetButtonMask)
2140 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002141 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002142 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002143 }
2144 else
2145 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002146 phosphor::logging::log<phosphor::logging::level::INFO>(
2147 "reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002148 }
2149 }
2150 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2151 {
2152 resetButtonIface->set_property("ButtonPressed", false);
2153 }
2154 resetButtonEvent.async_wait(
2155 boost::asio::posix::stream_descriptor::wait_read,
2156 [](const boost::system::error_code ec) {
2157 if (ec)
2158 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002159 std::string errMsg =
2160 "reset button handler error: " + ec.message();
2161 phosphor::logging::log<phosphor::logging::level::ERR>(
2162 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002163 return;
2164 }
2165 resetButtonHandler();
2166 });
2167}
2168
Vijay Khemka04175c22020-10-09 14:28:11 -07002169#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002170static constexpr auto systemdBusname = "org.freedesktop.systemd1";
2171static constexpr auto systemdPath = "/org/freedesktop/systemd1";
2172static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
2173static constexpr auto systemTargetName = "chassis-system-reset.target";
2174
2175void systemReset()
2176{
2177 conn->async_method_call(
2178 [](boost::system::error_code ec) {
2179 if (ec)
2180 {
2181 phosphor::logging::log<phosphor::logging::level::ERR>(
2182 "Failed to call chassis system reset",
2183 phosphor::logging::entry("ERR=%s", ec.message().c_str()));
2184 }
2185 },
2186 systemdBusname, systemdPath, systemdInterface, "StartUnit",
2187 systemTargetName, "replace");
2188}
Vijay Khemka04175c22020-10-09 14:28:11 -07002189#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002190
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002191static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002192{
2193 conn->async_method_call(
2194 [](boost::system::error_code ec) {
2195 if (ec)
2196 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002197 phosphor::logging::log<phosphor::logging::level::INFO>(
2198 "failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002199 }
2200 },
Chen Yugang303bd582019-11-01 08:45:06 +08002201 "xyz.openbmc_project.Settings",
2202 "/xyz/openbmc_project/Chassis/Control/NMISource",
2203 "org.freedesktop.DBus.Properties", "Set",
2204 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
2205 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002206}
2207
2208static void nmiReset(void)
2209{
2210 static constexpr const uint8_t value = 1;
2211 const static constexpr int nmiOutPulseTimeMs = 200;
2212
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002213 phosphor::logging::log<phosphor::logging::level::INFO>("NMI out action");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002214 nmiOutLine.set_value(value);
Priyatharshan P70120512020-09-16 18:47:20 +05302215 std::string logMsg =
2216 nmiOutConfig.lineName + " set to " + std::to_string(value);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002217 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002218 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2219 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2220 // restore the NMI_OUT GPIO line back to the opposite value
2221 nmiOutLine.set_value(!value);
Priyatharshan P70120512020-09-16 18:47:20 +05302222 std::string logMsg = nmiOutConfig.lineName + " released";
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002223 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002224 if (ec)
2225 {
2226 // operation_aborted is expected if timer is canceled before
2227 // completion.
2228 if (ec != boost::asio::error::operation_aborted)
2229 {
Priyatharshan P70120512020-09-16 18:47:20 +05302230 std::string errMsg = nmiOutConfig.lineName +
2231 " async_wait failed: " + ec.message();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002232 phosphor::logging::log<phosphor::logging::level::ERR>(
2233 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002234 }
2235 }
2236 });
2237 // log to redfish
2238 nmiDiagIntLog();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002239 phosphor::logging::log<phosphor::logging::level::INFO>(
2240 "NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002241 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002242 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002243}
2244
2245static void nmiSourcePropertyMonitor(void)
2246{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002247 phosphor::logging::log<phosphor::logging::level::INFO>(
2248 "NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002249
2250 static std::unique_ptr<sdbusplus::bus::match::match> nmiSourceMatch =
2251 std::make_unique<sdbusplus::bus::match::match>(
2252 *conn,
2253 "type='signal',interface='org.freedesktop.DBus.Properties',"
Chen Yugang303bd582019-11-01 08:45:06 +08002254 "member='PropertiesChanged',arg0namespace='xyz.openbmc_project."
2255 "Chassis.Control."
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002256 "NMISource'",
2257 [](sdbusplus::message::message& msg) {
2258 std::string interfaceName;
2259 boost::container::flat_map<std::string,
2260 std::variant<bool, std::string>>
2261 propertiesChanged;
2262 std::string state;
2263 bool value = true;
2264 try
2265 {
2266 msg.read(interfaceName, propertiesChanged);
2267 if (propertiesChanged.begin()->first == "Enabled")
2268 {
2269 value =
2270 std::get<bool>(propertiesChanged.begin()->second);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002271 std::string logMsg =
2272 " NMI Enabled propertiesChanged value: " +
2273 std::to_string(value);
2274 phosphor::logging::log<phosphor::logging::level::INFO>(
2275 logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002276 nmiEnabled = value;
2277 if (nmiEnabled)
2278 {
2279 nmiReset();
2280 }
2281 }
2282 }
2283 catch (std::exception& e)
2284 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002285 phosphor::logging::log<phosphor::logging::level::ERR>(
2286 "Unable to read NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002287 return;
2288 }
2289 });
2290}
2291
2292static void setNmiSource()
2293{
2294 conn->async_method_call(
2295 [](boost::system::error_code ec) {
2296 if (ec)
2297 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002298 phosphor::logging::log<phosphor::logging::level::ERR>(
2299 "failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002300 }
2301 },
Chen Yugang303bd582019-11-01 08:45:06 +08002302 "xyz.openbmc_project.Settings",
2303 "/xyz/openbmc_project/Chassis/Control/NMISource",
2304 "org.freedesktop.DBus.Properties", "Set",
2305 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
2306 std::variant<std::string>{"xyz.openbmc_project.Chassis.Control."
2307 "NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002308 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002309 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002310}
2311
2312static void nmiButtonHandler()
2313{
2314 gpiod::line_event gpioLineEvent = nmiButtonLine.event_read();
2315
2316 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2317 {
2318 nmiButtonPressLog();
2319 nmiButtonIface->set_property("ButtonPressed", true);
2320 if (nmiButtonMasked)
2321 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002322 phosphor::logging::log<phosphor::logging::level::INFO>(
2323 "NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002324 }
2325 else
2326 {
2327 setNmiSource();
2328 }
2329 }
2330 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2331 {
2332 nmiButtonIface->set_property("ButtonPressed", false);
2333 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002334 nmiButtonEvent.async_wait(
2335 boost::asio::posix::stream_descriptor::wait_read,
2336 [](const boost::system::error_code ec) {
2337 if (ec)
2338 {
2339 std::string errMsg =
2340 "NMI button handler error: " + ec.message();
2341 phosphor::logging::log<phosphor::logging::level::ERR>(
2342 errMsg.c_str());
2343 return;
2344 }
2345 nmiButtonHandler();
2346 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002347}
2348
2349static void idButtonHandler()
2350{
2351 gpiod::line_event gpioLineEvent = idButtonLine.event_read();
2352
2353 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2354 {
2355 idButtonIface->set_property("ButtonPressed", true);
2356 }
2357 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2358 {
2359 idButtonIface->set_property("ButtonPressed", false);
2360 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002361 idButtonEvent.async_wait(
2362 boost::asio::posix::stream_descriptor::wait_read,
2363 [](const boost::system::error_code& ec) {
2364 if (ec)
2365 {
2366 std::string errMsg = "ID button handler error: " + ec.message();
2367 phosphor::logging::log<phosphor::logging::level::ERR>(
2368 errMsg.c_str());
2369 return;
2370 }
2371 idButtonHandler();
2372 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002373}
2374
Jason M. Billsfb957332021-01-28 13:18:46 -08002375static void pltRstHandler(bool pltRst)
2376{
2377 if (pltRst)
2378 {
2379 sendPowerControlEvent(Event::pltRstDeAssert);
2380 }
2381 else
2382 {
2383 sendPowerControlEvent(Event::pltRstAssert);
2384 }
2385}
2386
2387static void hostMiscHandler(sdbusplus::message::message& msg)
2388{
2389 std::string interfaceName;
2390 boost::container::flat_map<std::string, std::variant<bool>>
2391 propertiesChanged;
2392 bool pltRst;
2393 try
2394 {
2395 msg.read(interfaceName, propertiesChanged);
2396 }
2397 catch (std::exception& e)
2398 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002399 phosphor::logging::log<phosphor::logging::level::ERR>(
2400 "Unable to read Host Misc status");
Jason M. Billsfb957332021-01-28 13:18:46 -08002401 return;
2402 }
2403 if (propertiesChanged.empty())
2404 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002405 phosphor::logging::log<phosphor::logging::level::ERR>(
2406 "ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002407 return;
2408 }
2409
2410 for (auto& [property, value] : propertiesChanged)
2411 {
2412 if (property == "ESpiPlatformReset")
2413 {
2414 bool* pltRst = std::get_if<bool>(&value);
2415 if (pltRst == nullptr)
2416 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002417 std::string errMsg = property + " property invalid";
2418 phosphor::logging::log<phosphor::logging::level::ERR>(
2419 errMsg.c_str());
Jason M. Billsfb957332021-01-28 13:18:46 -08002420 return;
2421 }
2422 pltRstHandler(*pltRst);
2423 }
2424 }
2425}
2426
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002427static void postCompleteHandler()
2428{
2429 gpiod::line_event gpioLineEvent = postCompleteLine.event_read();
2430
2431 bool postComplete =
2432 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002433 if (postComplete)
2434 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002435 sendPowerControlEvent(Event::postCompleteAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002436 osIface->set_property("OperatingSystemState", std::string("Standby"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002437 }
2438 else
2439 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002440 sendPowerControlEvent(Event::postCompleteDeAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002441 osIface->set_property("OperatingSystemState", std::string("Inactive"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002442 }
2443 postCompleteEvent.async_wait(
2444 boost::asio::posix::stream_descriptor::wait_read,
2445 [](const boost::system::error_code ec) {
2446 if (ec)
2447 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002448 std::string errMsg =
2449 "POST complete handler error: " + ec.message();
2450 phosphor::logging::log<phosphor::logging::level::ERR>(
2451 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002452 return;
2453 }
2454 postCompleteHandler();
2455 });
2456}
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302457
2458static int loadConfigValues()
2459{
2460 const std::string configFilePath =
2461 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2462 ".json";
2463 std::ifstream configFile(configFilePath.c_str());
2464 if (!configFile.is_open())
2465 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002466 phosphor::logging::log<phosphor::logging::level::ERR>(
2467 "loadConfigValues : Cannot open config path");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302468 return -1;
2469 }
Zev Weiss1aa08b22021-09-15 17:06:20 -05002470 auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302471
Priyatharshan P70120512020-09-16 18:47:20 +05302472 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302473 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002474 phosphor::logging::log<phosphor::logging::level::ERR>(
2475 "Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302476 return -1;
2477 }
Priyatharshan P70120512020-09-16 18:47:20 +05302478 auto gpios = jsonData["gpio_configs"];
2479 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302480
Priyatharshan P70120512020-09-16 18:47:20 +05302481 ConfigData* tempGpioData;
2482
2483 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302484 {
Priyatharshan P70120512020-09-16 18:47:20 +05302485 if (!gpioConfig.contains("Name"))
2486 {
2487 phosphor::logging::log<phosphor::logging::level::ERR>(
2488 "The 'Name' field must be defined in Json file");
2489 return -1;
2490 }
2491
2492 // Iterate through the powersignal map to check if the gpio json config
2493 // entry is valid
2494 std::string gpioName = gpioConfig["Name"];
2495 auto signalMapIter = powerSignalMap.find(gpioName);
2496 if (signalMapIter == powerSignalMap.end())
2497 {
2498 std::string errMsg = "Undefined Name : " + gpioName;
2499 phosphor::logging::log<phosphor::logging::level::ERR>(
2500 errMsg.c_str());
2501 return -1;
2502 }
2503
2504 // assign the power signal name to the corresponding structure reference
2505 // from map then fillup the structure with coressponding json config
2506 // value
2507 tempGpioData = signalMapIter->second;
2508 tempGpioData->name = gpioName;
2509
2510 if (!gpioConfig.contains("Type"))
2511 {
2512 phosphor::logging::log<phosphor::logging::level::ERR>(
2513 "The \'Type\' field must be defined in Json file");
2514 return -1;
2515 }
2516
2517 std::string signalType = gpioConfig["Type"];
2518 if (signalType == "GPIO")
2519 {
2520 tempGpioData->type = ConfigType::GPIO;
2521 }
2522 else if (signalType == "DBUS")
2523 {
2524 tempGpioData->type = ConfigType::DBUS;
2525 }
2526 else
2527 {
2528 std::string errMsg = "Undefined Type : " + signalType;
2529 phosphor::logging::log<phosphor::logging::level::ERR>(
2530 errMsg.c_str());
2531 return -1;
2532 }
2533
2534 if (tempGpioData->type == ConfigType::GPIO)
2535 {
2536 if (gpioConfig.contains("LineName"))
2537 {
2538 tempGpioData->lineName = gpioConfig["LineName"];
2539 }
2540 else
2541 {
2542 phosphor::logging::log<phosphor::logging::level::ERR>(
2543 "The \'LineName\' field must be defined for GPIO "
2544 "configuration");
2545 return -1;
2546 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002547 if (gpioConfig.contains("Polarity"))
2548 {
2549 std::string polarity = gpioConfig["Polarity"];
2550 if (polarity == "ActiveLow")
2551 {
2552 tempGpioData->polarity = false;
2553 }
2554 else if (polarity == "ActiveHigh")
2555 {
2556 tempGpioData->polarity = true;
2557 }
2558 else
2559 {
2560 std::string errMsg =
2561 "Polarity defined but not properly setup. Please "
2562 "only ActiveHigh or ActiveLow. Currently set to " +
2563 polarity;
2564 phosphor::logging::log<phosphor::logging::level::ERR>(
2565 errMsg.c_str());
2566 return -1;
2567 }
2568 }
2569 else
2570 {
2571 std::string errMsg =
2572 "Polarity field not found for " + tempGpioData->lineName;
2573 phosphor::logging::log<phosphor::logging::level::ERR>(
2574 errMsg.c_str());
2575 return -1;
2576 }
Priyatharshan P70120512020-09-16 18:47:20 +05302577 }
2578 else
2579 {
2580 // if dbus based gpio config is defined read and update the dbus
2581 // params corresponding to the gpio config instance
2582 for (auto& [key, dbusParamName] : dbusParams)
2583 {
2584 if (!gpios.contains(dbusParamName))
2585 {
2586 std::string errMsg =
2587 "The " + dbusParamName +
2588 "field must be defined for Dbus configuration ";
2589 phosphor::logging::log<phosphor::logging::level::ERR>(
2590 errMsg.c_str());
2591 return -1;
2592 }
2593 }
2594 tempGpioData->dbusName = gpios[dbusParams[DbusConfigType::name]];
2595 tempGpioData->path = gpios[dbusParams[DbusConfigType::path]];
2596 tempGpioData->interface =
2597 gpios[dbusParams[DbusConfigType::interface]];
2598 tempGpioData->lineName =
2599 gpios[dbusParams[DbusConfigType::property]];
2600 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302601 }
2602
Priyatharshan P70120512020-09-16 18:47:20 +05302603 // read and store the timer values from json config to Timer Map
2604 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302605 {
Priyatharshan P70120512020-09-16 18:47:20 +05302606 if (timers.contains(key.c_str()))
2607 {
2608 timerValue = timers[key.c_str()];
2609 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302610 }
2611
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302612 return 0;
2613}
Zev Weissa8f116a2021-09-01 21:08:30 -05002614
2615static bool getDbusMsgGPIOState(sdbusplus::message::message& msg,
2616 const std::string& lineName, bool& value)
2617{
2618 std::string thresholdInterface;
2619 std::string event;
2620 boost::container::flat_map<std::string, std::variant<bool>>
2621 propertiesChanged;
2622 try
2623 {
2624 msg.read(thresholdInterface, propertiesChanged);
2625 if (propertiesChanged.empty())
2626 {
2627 return false;
2628 }
2629
2630 event = propertiesChanged.begin()->first;
2631 if (event.empty() || event != lineName)
2632 {
2633 return false;
2634 }
2635
2636 value = std::get<bool>(propertiesChanged.begin()->second);
2637 return true;
2638 }
2639 catch (std::exception& e)
2640 {
2641 std::string logmsg =
2642 "exception while reading dbus property: " + lineName;
2643 phosphor::logging::log<phosphor::logging::level::ERR>(logmsg.c_str());
2644 return false;
2645 }
2646}
2647
2648static sdbusplus::bus::match::match
2649 dbusGPIOMatcher(const ConfigData& cfg, std::function<void(bool)> onMatch)
2650{
2651 auto pulseEventMatcherCallback =
2652 [&cfg, onMatch](sdbusplus::message::message& msg) {
2653 bool value = false;
2654 if (!getDbusMsgGPIOState(msg, cfg.lineName, value))
2655 {
2656 return;
2657 }
2658 onMatch(value);
2659 };
2660
2661 return sdbusplus::bus::match::match(
2662 static_cast<sdbusplus::bus::bus&>(*conn),
2663 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2664 "PropertiesChanged',arg0='" +
2665 cfg.dbusName + "'",
2666 std::move(pulseEventMatcherCallback));
2667}
2668
Priyatharshan P70120512020-09-16 18:47:20 +05302669inline static sdbusplus::bus::match::match powerButtonEventMonitor()
2670{
Zev Weissa8f116a2021-09-01 21:08:30 -05002671 auto onMatch = [](bool value) {
Priyatharshan P70120512020-09-16 18:47:20 +05302672 if (value == false)
2673 {
2674 powerButtonPressLog();
2675 powerButtonIface->set_property("ButtonPressed", true);
2676 if (!powerButtonMask)
2677 {
2678 sendPowerControlEvent(Event::powerButtonPressed);
2679 addRestartCause(RestartCause::powerButton);
2680 }
2681 else
2682 {
2683 phosphor::logging::log<phosphor::logging::level::ERR>(
2684 "power button press masked\n");
2685 }
2686 }
2687 else
2688 {
2689 powerButtonIface->set_property("ButtonPressed", false);
2690 }
2691 };
2692
Zev Weissa8f116a2021-09-01 21:08:30 -05002693 return dbusGPIOMatcher(powerButtonConfig, std::move(onMatch));
Priyatharshan P70120512020-09-16 18:47:20 +05302694}
2695
2696inline static sdbusplus::bus::match::match resetButtonEventMonitor()
2697{
Zev Weissa8f116a2021-09-01 21:08:30 -05002698 auto onMatch = [](bool value) {
Priyatharshan P70120512020-09-16 18:47:20 +05302699 if (value == false)
2700 {
2701 resetButtonPressLog();
2702 resetButtonIface->set_property("ButtonPressed", true);
2703 if (!resetButtonMask)
2704 {
2705 sendPowerControlEvent(Event::resetButtonPressed);
2706 addRestartCause(RestartCause::resetButton);
2707 }
2708 else
2709 {
2710 phosphor::logging::log<phosphor::logging::level::ERR>(
2711 "reset button press masked");
2712 }
2713 }
2714 else
2715 {
2716 resetButtonIface->set_property("ButtonPressed", false);
2717 }
2718 };
2719
Zev Weissa8f116a2021-09-01 21:08:30 -05002720 return dbusGPIOMatcher(resetButtonConfig, std::move(onMatch));
Priyatharshan P70120512020-09-16 18:47:20 +05302721}
2722
2723inline static sdbusplus::bus::match::match powerOkEventMonitor()
2724{
Zev Weissa8f116a2021-09-01 21:08:30 -05002725 auto onMatch = [](bool value) {
Priyatharshan P70120512020-09-16 18:47:20 +05302726 Event powerControlEvent =
2727 value ? Event::psPowerOKAssert : Event::psPowerOKDeAssert;
2728 sendPowerControlEvent(powerControlEvent);
2729 };
2730
Zev Weissa8f116a2021-09-01 21:08:30 -05002731 return dbusGPIOMatcher(powerOkConfig, std::move(onMatch));
Priyatharshan P70120512020-09-16 18:47:20 +05302732}
2733
2734inline static sdbusplus::bus::match::match sioPwrGoodEventMonitor()
2735{
Zev Weissa8f116a2021-09-01 21:08:30 -05002736 auto onMatch = [](bool value) {
Priyatharshan P70120512020-09-16 18:47:20 +05302737 Event powerControlEvent =
2738 value ? Event::sioPowerGoodAssert : Event::sioPowerGoodDeAssert;
Priyatharshan P70120512020-09-16 18:47:20 +05302739 sendPowerControlEvent(powerControlEvent);
2740 };
2741
Zev Weissa8f116a2021-09-01 21:08:30 -05002742 return dbusGPIOMatcher(sioPwrGoodConfig, std::move(onMatch));
Priyatharshan P70120512020-09-16 18:47:20 +05302743}
2744
2745inline static sdbusplus::bus::match::match sioOnControlEventMonitor()
2746{
Zev Weissa8f116a2021-09-01 21:08:30 -05002747 auto onMatch = [](bool value) {
Priyatharshan P70120512020-09-16 18:47:20 +05302748 std::string errMsg =
2749 "SIO_ONCONTROL value changed : " + std::to_string(value);
2750 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
2751 };
2752
Zev Weissa8f116a2021-09-01 21:08:30 -05002753 return dbusGPIOMatcher(sioOnControlConfig, std::move(onMatch));
Priyatharshan P70120512020-09-16 18:47:20 +05302754}
2755
2756inline static sdbusplus::bus::match::match sioS5EventMonitor()
2757{
Zev Weissa8f116a2021-09-01 21:08:30 -05002758 auto onMatch = [](bool value) {
Priyatharshan P70120512020-09-16 18:47:20 +05302759 Event powerControlEvent =
2760 value ? Event::sioS5DeAssert : Event::sioS5Assert;
2761 sendPowerControlEvent(powerControlEvent);
2762 };
2763
Zev Weissa8f116a2021-09-01 21:08:30 -05002764 return dbusGPIOMatcher(sioS5Config, std::move(onMatch));
Priyatharshan P70120512020-09-16 18:47:20 +05302765}
2766
2767inline static sdbusplus::bus::match::match nmiButtonEventMonitor()
2768{
Zev Weissa8f116a2021-09-01 21:08:30 -05002769 auto onMatch = [](bool value) {
Priyatharshan P70120512020-09-16 18:47:20 +05302770 if (value)
2771 {
2772 nmiButtonIface->set_property("ButtonPressed", false);
2773 }
2774 else
2775 {
2776 nmiButtonPressLog();
2777 nmiButtonIface->set_property("ButtonPressed", true);
2778 if (nmiButtonMasked)
2779 {
2780 phosphor::logging::log<phosphor::logging::level::ERR>(
2781 "NMI button press masked");
2782 }
2783 else
2784 {
2785 setNmiSource();
2786 }
2787 }
2788 };
2789
Zev Weissa8f116a2021-09-01 21:08:30 -05002790 return dbusGPIOMatcher(nmiButtonConfig, std::move(onMatch));
Priyatharshan P70120512020-09-16 18:47:20 +05302791}
2792
2793inline static sdbusplus::bus::match::match idButtonEventMonitor()
2794{
Zev Weissa8f116a2021-09-01 21:08:30 -05002795 auto onMatch = [](bool value) {
Priyatharshan P70120512020-09-16 18:47:20 +05302796 if (value)
2797 {
2798 idButtonIface->set_property("ButtonPressed", false);
2799 }
2800 else
2801 {
2802 idButtonIface->set_property("ButtonPressed", true);
2803 }
2804 };
2805
Zev Weissa8f116a2021-09-01 21:08:30 -05002806 return dbusGPIOMatcher(idButtonConfig, std::move(onMatch));
Priyatharshan P70120512020-09-16 18:47:20 +05302807}
2808
2809inline static sdbusplus::bus::match::match postCompleteEventMonitor()
2810{
Zev Weissa8f116a2021-09-01 21:08:30 -05002811 auto onMatch = [](bool value) {
Priyatharshan P70120512020-09-16 18:47:20 +05302812 if (value)
2813 {
2814 sendPowerControlEvent(Event::postCompleteDeAssert);
2815 osIface->set_property("OperatingSystemState",
2816 std::string("Inactive"));
2817 }
2818 else
2819 {
2820 sendPowerControlEvent(Event::postCompleteAssert);
2821 osIface->set_property("OperatingSystemState",
2822 std::string("Standby"));
2823 }
2824 };
2825
Zev Weissa8f116a2021-09-01 21:08:30 -05002826 return dbusGPIOMatcher(postCompleteConfig, std::move(onMatch));
Priyatharshan P70120512020-09-16 18:47:20 +05302827}
2828
2829int getProperty(ConfigData& configData)
2830{
2831 auto method = conn->new_method_call(
2832 configData.dbusName.c_str(), configData.path.c_str(),
2833 "org.freedesktop.DBus.Properties", "Get");
2834 method.append(configData.interface.c_str(), configData.lineName.c_str());
2835
2836 auto reply = conn->call(method);
2837 if (reply.is_method_error())
2838 {
2839 phosphor::logging::log<phosphor::logging::level::ERR>(
2840 "Error reading from Bus");
2841 return -1;
2842 }
2843 std::variant<int> resp;
2844 reply.read(resp);
2845 auto respValue = std::get_if<int>(&resp);
2846 if (!respValue)
2847 {
2848 phosphor::logging::log<phosphor::logging::level::ERR>(
2849 "Error reading response");
2850 return -1;
2851 }
2852 return (*respValue);
2853}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002854} // namespace power_control
2855
2856int main(int argc, char* argv[])
2857{
Lei YU92caa4c2021-02-23 16:59:25 +08002858 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05302859
2860 if (argc > 1)
2861 {
2862 node = argv[1];
2863 }
2864 std::string infoMsg =
2865 "Start Chassis power control service for host : " + node;
2866 phosphor::logging::log<phosphor::logging::level::INFO>(infoMsg.c_str());
2867
Lei YU92caa4c2021-02-23 16:59:25 +08002868 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002869
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302870 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08002871 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302872 {
Lei YU92caa4c2021-02-23 16:59:25 +08002873 std::string errMsg = "Host" + node + ": " + "Error in Parsing...";
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002874 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302875 }
Naveen Mosesec972d82021-07-16 21:19:23 +05302876 /* Currently for single host based systems additional busname is added
2877 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
2878 Going forward for single hosts the old bus name without zero numbering
2879 will be removed when all other applications adapted to the
2880 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
2881
2882 if (node == "0")
2883 {
2884 // Request all the dbus names
2885 conn->request_name(hostDbusName.c_str());
2886 conn->request_name(chassisDbusName.c_str());
2887 conn->request_name(osDbusName.c_str());
2888 conn->request_name(buttonDbusName.c_str());
2889 conn->request_name(nmiDbusName.c_str());
2890 conn->request_name(rstCauseDbusName.c_str());
2891 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302892
Zev Weissc4005bd2021-09-01 22:30:23 -05002893 hostDbusName += node;
2894 chassisDbusName += node;
2895 osDbusName += node;
2896 buttonDbusName += node;
2897 nmiDbusName += node;
2898 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002899
Priyatharshan P70120512020-09-16 18:47:20 +05302900 // Request all the dbus names
2901 conn->request_name(hostDbusName.c_str());
2902 conn->request_name(chassisDbusName.c_str());
2903 conn->request_name(osDbusName.c_str());
2904 conn->request_name(buttonDbusName.c_str());
2905 conn->request_name(nmiDbusName.c_str());
2906 conn->request_name(rstCauseDbusName.c_str());
2907
2908 if (sioPwrGoodConfig.lineName.empty() ||
2909 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05302910 {
Lei YU92caa4c2021-02-23 16:59:25 +08002911 sioEnabled = false;
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002912 phosphor::logging::log<phosphor::logging::level::INFO>(
2913 "SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05302914 }
2915
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002916 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302917 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002918 {
Priyatharshan P70120512020-09-16 18:47:20 +05302919 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
2920 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302921 {
2922 return -1;
2923 }
2924 }
Priyatharshan P70120512020-09-16 18:47:20 +05302925 else if (powerOkConfig.type == ConfigType::DBUS)
2926 {
2927
2928 static sdbusplus::bus::match::match powerOkEventMonitor =
2929 power_control::powerOkEventMonitor();
2930 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302931 else
2932 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002933 phosphor::logging::log<phosphor::logging::level::ERR>(
2934 "PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002935 return -1;
2936 }
2937
Lei YU92caa4c2021-02-23 16:59:25 +08002938 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002939 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05302940 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302941 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302942 {
Priyatharshan P70120512020-09-16 18:47:20 +05302943 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
2944 sioPowerGoodHandler, sioPowerGoodLine,
2945 sioPowerGoodEvent))
2946 {
2947 return -1;
2948 }
2949 }
2950 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
2951 {
2952 static sdbusplus::bus::match::match sioPwrGoodEventMonitor =
2953 power_control::sioPwrGoodEventMonitor();
2954 }
2955 else
2956 {
2957 phosphor::logging::log<phosphor::logging::level::ERR>(
2958 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302959 return -1;
2960 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002961
Priyatharshan P19c47a32020-08-12 18:16:43 +05302962 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302963 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302964 {
Priyatharshan P70120512020-09-16 18:47:20 +05302965 if (!requestGPIOEvents(sioOnControlConfig.lineName,
2966 sioOnControlHandler, sioOnControlLine,
2967 sioOnControlEvent))
2968 {
2969 return -1;
2970 }
2971 }
2972 else if (sioOnControlConfig.type == ConfigType::DBUS)
2973 {
2974 static sdbusplus::bus::match::match sioOnControlEventMonitor =
2975 power_control::sioOnControlEventMonitor();
2976 }
2977 else
2978 {
2979 phosphor::logging::log<phosphor::logging::level::ERR>(
2980 "sioOnControl name should be configured from json"
2981 "config file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302982 return -1;
2983 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002984
Priyatharshan P19c47a32020-08-12 18:16:43 +05302985 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302986 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302987 {
Priyatharshan P70120512020-09-16 18:47:20 +05302988 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
2989 sioS5Line, sioS5Event))
2990 {
2991 return -1;
2992 }
2993 }
2994 else if (sioS5Config.type == ConfigType::DBUS)
2995 {
2996 static sdbusplus::bus::match::match sioS5EventMonitor =
2997 power_control::sioS5EventMonitor();
2998 }
2999 else
3000 {
3001 phosphor::logging::log<phosphor::logging::level::ERR>(
3002 "sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303003 return -1;
3004 }
3005 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003006
3007 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303008 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003009 {
Priyatharshan P70120512020-09-16 18:47:20 +05303010 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
Lei YU92caa4c2021-02-23 16:59:25 +08003011 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303012 {
3013 return -1;
3014 }
3015 }
Priyatharshan P70120512020-09-16 18:47:20 +05303016 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303017 {
Priyatharshan P70120512020-09-16 18:47:20 +05303018 static sdbusplus::bus::match::match powerButtonEventMonitor =
3019 power_control::powerButtonEventMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003020 }
3021
3022 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303023 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003024 {
Priyatharshan P70120512020-09-16 18:47:20 +05303025 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
Lei YU92caa4c2021-02-23 16:59:25 +08003026 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303027 {
3028 return -1;
3029 }
3030 }
Priyatharshan P70120512020-09-16 18:47:20 +05303031 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303032 {
Priyatharshan P70120512020-09-16 18:47:20 +05303033 static sdbusplus::bus::match::match resetButtonEventMonitor =
3034 power_control::resetButtonEventMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003035 }
3036
3037 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303038 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303039 {
Priyatharshan P70120512020-09-16 18:47:20 +05303040 if (!nmiButtonConfig.lineName.empty())
3041 {
3042 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
3043 nmiButtonLine, nmiButtonEvent);
3044 }
3045 }
3046 else if (nmiButtonConfig.type == ConfigType::DBUS)
3047 {
3048 static sdbusplus::bus::match::match nmiButtonEventMonitor =
3049 power_control::nmiButtonEventMonitor();
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303050 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003051
3052 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303053 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303054 {
Priyatharshan P70120512020-09-16 18:47:20 +05303055 if (!idButtonConfig.lineName.empty())
3056 {
3057 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
3058 idButtonLine, idButtonEvent);
3059 }
3060 }
3061 else if (idButtonConfig.type == ConfigType::DBUS)
3062 {
3063 static sdbusplus::bus::match::match idButtonEventMonitor =
3064 power_control::idButtonEventMonitor();
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303065 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003066
Jason M. Billsfb957332021-01-28 13:18:46 -08003067#ifdef USE_PLT_RST
3068 sdbusplus::bus::match::match pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08003069 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08003070 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
3071 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08003072 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08003073#endif
3074
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003075 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303076 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003077 {
Priyatharshan P70120512020-09-16 18:47:20 +05303078 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
Lei YU92caa4c2021-02-23 16:59:25 +08003079 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303080 {
3081 return -1;
3082 }
3083 }
Priyatharshan P70120512020-09-16 18:47:20 +05303084 else if (postCompleteConfig.type == ConfigType::DBUS)
3085 {
3086 static sdbusplus::bus::match::match postCompleteEventMonitor =
3087 power_control::postCompleteEventMonitor();
3088 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303089 else
3090 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003091 phosphor::logging::log<phosphor::logging::level::ERR>(
3092 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003093 return -1;
3094 }
3095
3096 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05303097 if (!nmiOutConfig.lineName.empty())
3098 {
3099 setGPIOOutput(nmiOutConfig.lineName, 0, nmiOutLine);
3100 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003101
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003102 // Initialize POWER_OUT and RESET_OUT GPIO.
3103 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05303104 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003105 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07003106 if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
3107 line))
Priyatharshan P70120512020-09-16 18:47:20 +05303108 {
3109 return -1;
3110 }
3111 }
3112 else
3113 {
3114 phosphor::logging::log<phosphor::logging::level::ERR>(
3115 "powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003116 return -1;
3117 }
3118
Priyatharshan P70120512020-09-16 18:47:20 +05303119 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003120 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07003121 if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
3122 line))
Priyatharshan P70120512020-09-16 18:47:20 +05303123 {
3124 return -1;
3125 }
3126 }
3127 else
3128 {
3129 phosphor::logging::log<phosphor::logging::level::ERR>(
3130 "ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003131 return -1;
3132 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003133 // Release line
3134 line.reset();
3135
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003136 // Initialize the power state
Lei YU92caa4c2021-02-23 16:59:25 +08003137 powerState = PowerState::off;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003138 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05303139
3140 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003141 {
Jean-Marie Verdun61b4a5b2021-09-19 08:53:28 -04003142 if (psPowerOKLine.get_value() > 0 ||
3143 sioPowerGoodLine.get_value() == sioPwrGoodConfig.polarity)
Priyatharshan P70120512020-09-16 18:47:20 +05303144 {
3145 powerState = PowerState::on;
3146 }
3147 }
3148 else
3149 {
3150 if (getProperty(powerOkConfig))
3151 {
3152 powerState = PowerState::on;
3153 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003154 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003155 // Initialize the power state storage
Lei YU92caa4c2021-02-23 16:59:25 +08003156 if (initializePowerStateStorage() < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003157 {
3158 return -1;
3159 }
3160
3161 // Check if we need to start the Power Restore policy
Lei YU92caa4c2021-02-23 16:59:25 +08003162 powerRestorePolicyCheck();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003163
Lei YU92caa4c2021-02-23 16:59:25 +08003164 if (nmiOutLine)
3165 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003166
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003167 phosphor::logging::log<phosphor::logging::level::INFO>(
3168 "Initializing power state. ");
Lei YU92caa4c2021-02-23 16:59:25 +08003169 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003170
3171 // Power Control Service
3172 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003173 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003174
3175 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303176 hostIface =
3177 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
3178 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003179 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08003180 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003181 "RequestedHostTransition",
3182 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
3183 [](const std::string& requested, std::string& resp) {
3184 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
3185 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003186 // if power button is masked, ignore this
3187 if (!powerButtonMask)
3188 {
3189 sendPowerControlEvent(Event::gracefulPowerOffRequest);
3190 addRestartCause(RestartCause::command);
3191 }
3192 else
3193 {
3194 phosphor::logging::log<phosphor::logging::level::INFO>(
3195 "Power Button Masked.");
3196 throw std::invalid_argument("Transition Request Masked");
3197 return 0;
3198 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003199 }
3200 else if (requested ==
3201 "xyz.openbmc_project.State.Host.Transition.On")
3202 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003203 // if power button is masked, ignore this
3204 if (!powerButtonMask)
3205 {
3206 sendPowerControlEvent(Event::powerOnRequest);
3207 addRestartCause(RestartCause::command);
3208 }
3209 else
3210 {
3211 phosphor::logging::log<phosphor::logging::level::INFO>(
3212 "Power Button Masked.");
3213 throw std::invalid_argument("Transition Request Masked");
3214 return 0;
3215 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003216 }
3217 else if (requested ==
3218 "xyz.openbmc_project.State.Host.Transition.Reboot")
3219 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003220 // if power button is masked, ignore this
3221 if (!powerButtonMask)
3222 {
3223 sendPowerControlEvent(Event::powerCycleRequest);
3224 addRestartCause(RestartCause::command);
3225 }
3226 else
3227 {
3228 phosphor::logging::log<phosphor::logging::level::INFO>(
3229 "Power Button Masked.");
3230 throw std::invalid_argument("Transition Request Masked");
3231 return 0;
3232 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003233 }
3234 else if (requested == "xyz.openbmc_project.State.Host.Transition."
3235 "GracefulWarmReboot")
3236 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003237 // if reset button is masked, ignore this
3238 if (!resetButtonMask)
3239 {
3240 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
3241 addRestartCause(RestartCause::command);
3242 }
3243 else
3244 {
3245 phosphor::logging::log<phosphor::logging::level::INFO>(
3246 "Reset Button Masked.");
3247 throw std::invalid_argument("Transition Request Masked");
3248 return 0;
3249 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003250 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003251 else if (requested == "xyz.openbmc_project.State.Host.Transition."
3252 "ForceWarmReboot")
3253 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003254 // if reset button is masked, ignore this
3255 if (!resetButtonMask)
3256 {
3257 sendPowerControlEvent(Event::resetRequest);
3258 addRestartCause(RestartCause::command);
3259 }
3260 else
3261 {
3262 phosphor::logging::log<phosphor::logging::level::INFO>(
3263 "Reset Button Masked.");
3264 throw std::invalid_argument("Transition Request Masked");
3265 return 0;
3266 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003267 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003268 else
3269 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003270 phosphor::logging::log<phosphor::logging::level::ERR>(
3271 "Unrecognized host state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003272 throw std::invalid_argument("Unrecognized Transition Request");
3273 return 0;
3274 }
3275 resp = requested;
3276 return 1;
3277 });
Lei YU92caa4c2021-02-23 16:59:25 +08003278 hostIface->register_property("CurrentHostState",
3279 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003280
Lei YU92caa4c2021-02-23 16:59:25 +08003281 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003282
3283 // Chassis Control Service
3284 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003285 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003286
3287 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003288 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05303289 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003290 "xyz.openbmc_project.State.Chassis");
3291
Lei YU92caa4c2021-02-23 16:59:25 +08003292 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003293 "RequestedPowerTransition",
3294 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
3295 [](const std::string& requested, std::string& resp) {
3296 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
3297 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003298 // if power button is masked, ignore this
3299 if (!powerButtonMask)
3300 {
3301 sendPowerControlEvent(Event::powerOffRequest);
3302 addRestartCause(RestartCause::command);
3303 }
3304 else
3305 {
3306 phosphor::logging::log<phosphor::logging::level::INFO>(
3307 "Power Button Masked.");
3308 throw std::invalid_argument("Transition Request Masked");
3309 return 0;
3310 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003311 }
3312 else if (requested ==
3313 "xyz.openbmc_project.State.Chassis.Transition.On")
3314 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003315 // if power button is masked, ignore this
3316 if (!powerButtonMask)
3317 {
3318 sendPowerControlEvent(Event::powerOnRequest);
3319 addRestartCause(RestartCause::command);
3320 }
3321 else
3322 {
3323 phosphor::logging::log<phosphor::logging::level::INFO>(
3324 "Power Button Masked.");
3325 throw std::invalid_argument("Transition Request Masked");
3326 return 0;
3327 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003328 }
3329 else if (requested ==
3330 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3331 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003332 // if power button is masked, ignore this
3333 if (!powerButtonMask)
3334 {
3335 sendPowerControlEvent(Event::powerCycleRequest);
3336 addRestartCause(RestartCause::command);
3337 }
3338 else
3339 {
3340 phosphor::logging::log<phosphor::logging::level::INFO>(
3341 "Power Button Masked.");
3342 throw std::invalid_argument("Transition Request Masked");
3343 return 0;
3344 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003345 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003346 else
3347 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003348 phosphor::logging::log<phosphor::logging::level::ERR>(
3349 "Unrecognized chassis state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003350 throw std::invalid_argument("Unrecognized Transition Request");
3351 return 0;
3352 }
3353 resp = requested;
3354 return 1;
3355 });
Lei YU92caa4c2021-02-23 16:59:25 +08003356 chassisIface->register_property("CurrentPowerState",
3357 std::string(getChassisState(powerState)));
3358 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003359
Lei YU92caa4c2021-02-23 16:59:25 +08003360 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003361
Vijay Khemka04175c22020-10-09 14:28:11 -07003362#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003363 // Chassis System Service
3364 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003365 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003366
3367 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003368 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003369 "/xyz/openbmc_project/state/chassis_system0",
3370 "xyz.openbmc_project.State.Chassis");
3371
Lei YU92caa4c2021-02-23 16:59:25 +08003372 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003373 "RequestedPowerTransition",
3374 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3375 [](const std::string& requested, std::string& resp) {
3376 if (requested ==
3377 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3378 {
Lei YU92caa4c2021-02-23 16:59:25 +08003379 systemReset();
3380 addRestartCause(RestartCause::command);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003381 }
3382 else
3383 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003384 phosphor::logging::log<phosphor::logging::level::ERR>(
3385 "Unrecognized chassis system state transition request.");
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003386 throw std::invalid_argument("Unrecognized Transition Request");
3387 return 0;
3388 }
3389 resp = requested;
3390 return 1;
3391 });
Lei YU92caa4c2021-02-23 16:59:25 +08003392 chassisSysIface->register_property(
3393 "CurrentPowerState", std::string(getChassisState(powerState)));
3394 chassisSysIface->register_property("LastStateChangeTime",
3395 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003396
Lei YU92caa4c2021-02-23 16:59:25 +08003397 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003398
Naveen Moses117c34e2021-05-26 20:10:51 +05303399 if (!slotPowerConfig.lineName.empty())
3400 {
3401 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3402 {
3403 return -1;
3404 }
3405
3406 slotPowerState = SlotPowerState::off;
3407 if (slotPowerLine.get_value() > 0)
3408 {
3409 slotPowerState = SlotPowerState::on;
3410 }
3411
3412 chassisSlotIface = chassisSysServer.add_interface(
3413 "/xyz/openbmc_project/state/chassis_system" + node,
3414 "xyz.openbmc_project.State.Chassis");
3415 chassisSlotIface->register_property(
3416 "RequestedPowerTransition",
3417 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3418 [](const std::string& requested, std::string& resp) {
3419 if (requested ==
3420 "xyz.openbmc_project.State.Chassis.Transition.On")
3421 {
3422 slotPowerOn();
3423 }
3424 else if (requested ==
3425 "xyz.openbmc_project.State.Chassis.Transition.Off")
3426 {
3427 slotPowerOff();
3428 }
3429 else if (requested == "xyz.openbmc_project.State.Chassis."
3430 "Transition.PowerCycle")
3431 {
3432 slotPowerCycle();
3433 }
3434 else
3435 {
3436 phosphor::logging::log<phosphor::logging::level::ERR>(
3437 "Unrecognized chassis system state transition "
3438 "request.\n");
3439 throw std::invalid_argument(
3440 "Unrecognized Transition Request");
3441 return 0;
3442 }
3443 resp = requested;
3444 return 1;
3445 });
3446 chassisSlotIface->register_property(
3447 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3448 chassisSlotIface->register_property("LastStateChangeTime",
3449 getCurrentTimeMs());
3450 chassisSlotIface->initialize();
3451 }
3452#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003453 // Buttons Service
3454 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003455 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003456
Priyatharshan P70120512020-09-16 18:47:20 +05303457 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003458 {
Priyatharshan P70120512020-09-16 18:47:20 +05303459 // Power Button Interface
3460 power_control::powerButtonIface = buttonsServer.add_interface(
3461 "/xyz/openbmc_project/chassis/buttons/power",
3462 "xyz.openbmc_project.Chassis.Buttons");
3463
3464 powerButtonIface->register_property(
3465 "ButtonMasked", false, [](const bool requested, bool& current) {
3466 if (requested)
3467 {
3468 if (powerButtonMask)
3469 {
3470 return 1;
3471 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003472 if (!setGPIOOutput(powerOutConfig.lineName,
3473 !powerOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303474 powerButtonMask))
3475 {
3476 throw std::runtime_error("Failed to request GPIO");
3477 return 0;
3478 }
3479 phosphor::logging::log<phosphor::logging::level::INFO>(
3480 "Power Button Masked.");
3481 }
3482 else
3483 {
3484 if (!powerButtonMask)
3485 {
3486 return 1;
3487 }
3488 phosphor::logging::log<phosphor::logging::level::INFO>(
3489 "Power Button Un-masked");
3490 powerButtonMask.reset();
3491 }
3492 // Update the mask setting
3493 current = requested;
3494 return 1;
3495 });
3496
3497 // Check power button state
3498 bool powerButtonPressed;
3499 if (powerButtonConfig.type == ConfigType::GPIO)
3500 {
3501 powerButtonPressed = powerButtonLine.get_value() == 0;
3502 }
3503 else
3504 {
3505 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3506 }
3507
3508 powerButtonIface->register_property("ButtonPressed",
3509 powerButtonPressed);
3510
3511 powerButtonIface->initialize();
3512 }
3513
3514 if (!resetButtonConfig.lineName.empty())
3515 {
3516 // Reset Button Interface
3517
Lei YU92caa4c2021-02-23 16:59:25 +08003518 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003519 "/xyz/openbmc_project/chassis/buttons/reset",
3520 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003521
Lei YU92caa4c2021-02-23 16:59:25 +08003522 resetButtonIface->register_property(
John Wang6c090072020-09-30 13:32:16 +08003523 "ButtonMasked", false, [](const bool requested, bool& current) {
3524 if (requested)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003525 {
Lei YU92caa4c2021-02-23 16:59:25 +08003526 if (resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003527 {
3528 return 1;
3529 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003530 if (!setGPIOOutput(resetOutConfig.lineName,
3531 !resetOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303532 resetButtonMask))
John Wang6c090072020-09-30 13:32:16 +08003533 {
3534 throw std::runtime_error("Failed to request GPIO");
3535 return 0;
3536 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003537 phosphor::logging::log<phosphor::logging::level::INFO>(
3538 "Reset Button Masked.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003539 }
John Wang6c090072020-09-30 13:32:16 +08003540 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003541 {
Lei YU92caa4c2021-02-23 16:59:25 +08003542 if (!resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003543 {
3544 return 1;
3545 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003546 phosphor::logging::log<phosphor::logging::level::INFO>(
3547 "Reset Button Un-masked");
Lei YU92caa4c2021-02-23 16:59:25 +08003548 resetButtonMask.reset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003549 }
John Wang6c090072020-09-30 13:32:16 +08003550 // Update the mask setting
3551 current = requested;
3552 return 1;
3553 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003554
John Wang6c090072020-09-30 13:32:16 +08003555 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303556 bool resetButtonPressed;
3557 if (resetButtonConfig.type == ConfigType::GPIO)
3558 {
3559 resetButtonPressed = resetButtonLine.get_value() == 0;
3560 }
3561 else
3562 {
3563 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3564 }
3565
Lei YU92caa4c2021-02-23 16:59:25 +08003566 resetButtonIface->register_property("ButtonPressed",
3567 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003568
Lei YU92caa4c2021-02-23 16:59:25 +08003569 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003570 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003571
Lei YU92caa4c2021-02-23 16:59:25 +08003572 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003573 {
3574 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003575 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003576 "/xyz/openbmc_project/chassis/buttons/nmi",
3577 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003578
Lei YU92caa4c2021-02-23 16:59:25 +08003579 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003580 "ButtonMasked", false, [](const bool requested, bool& current) {
Lei YU92caa4c2021-02-23 16:59:25 +08003581 if (nmiButtonMasked == requested)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003582 {
3583 // NMI button mask is already set as requested, so no change
3584 return 1;
3585 }
3586 if (requested)
3587 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003588 phosphor::logging::log<phosphor::logging::level::INFO>(
3589 "NMI Button Masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003590 nmiButtonMasked = true;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003591 }
3592 else
3593 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003594 phosphor::logging::log<phosphor::logging::level::INFO>(
3595 "NMI Button Un-masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003596 nmiButtonMasked = false;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003597 }
3598 // Update the mask setting
Lei YU92caa4c2021-02-23 16:59:25 +08003599 current = nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003600 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003601 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003602
Vijay Khemka33a532d2019-11-14 16:50:35 -08003603 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303604 bool nmiButtonPressed;
3605 if (nmiButtonConfig.type == ConfigType::GPIO)
3606 {
3607 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3608 }
3609 else
3610 {
3611 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3612 }
3613
Lei YU92caa4c2021-02-23 16:59:25 +08003614 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003615
Lei YU92caa4c2021-02-23 16:59:25 +08003616 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003617 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003618
Lei YU92caa4c2021-02-23 16:59:25 +08003619 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003620 {
3621 // NMI out Service
3622 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003623 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003624
Vijay Khemka33a532d2019-11-14 16:50:35 -08003625 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303626 nmiOutIface = nmiOutServer.add_interface(
3627 "/xyz/openbmc_project/control/host" + node + "/nmi",
3628 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003629 nmiOutIface->register_method("NMI", nmiReset);
3630 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003631 }
Chen Yugang174ec662019-08-19 19:58:49 +08003632
Lei YU92caa4c2021-02-23 16:59:25 +08003633 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003634 {
3635 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003636 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003637 "/xyz/openbmc_project/chassis/buttons/id",
3638 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003639
Vijay Khemka33a532d2019-11-14 16:50:35 -08003640 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303641 bool idButtonPressed;
3642 if (idButtonConfig.type == ConfigType::GPIO)
3643 {
3644 idButtonPressed = idButtonLine.get_value() == 0;
3645 }
3646 else
3647 {
3648 idButtonPressed = getProperty(idButtonConfig) == 0;
3649 }
3650
Lei YU92caa4c2021-02-23 16:59:25 +08003651 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003652
Lei YU92caa4c2021-02-23 16:59:25 +08003653 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003654 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003655
3656 // OS State Service
3657 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003658 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003659
3660 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003661 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003662 "/xyz/openbmc_project/state/os",
3663 "xyz.openbmc_project.State.OperatingSystem.Status");
3664
3665 // Get the initial OS state based on POST complete
3666 // 0: Asserted, OS state is "Standby" (ready to boot)
3667 // 1: De-Asserted, OS state is "Inactive"
Priyatharshan P70120512020-09-16 18:47:20 +05303668 std::string osState;
3669 if (postCompleteConfig.type == ConfigType::GPIO)
3670 {
3671 osState = postCompleteLine.get_value() > 0 ? "Inactive" : "Standby";
3672 }
3673 else
3674 {
3675 osState = getProperty(postCompleteConfig) > 0 ? "Inactive" : "Standby";
3676 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003677
Lei YU92caa4c2021-02-23 16:59:25 +08003678 osIface->register_property("OperatingSystemState", std::string(osState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003679
Lei YU92caa4c2021-02-23 16:59:25 +08003680 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003681
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003682 // Restart Cause Service
3683 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003684 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003685
3686 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003687 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303688 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003689 "xyz.openbmc_project.Control.Host.RestartCause");
3690
Lei YU92caa4c2021-02-23 16:59:25 +08003691 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003692 "RestartCause",
3693 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3694
Lei YU92caa4c2021-02-23 16:59:25 +08003695 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003696 "RequestedRestartCause",
3697 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3698 [](const std::string& requested, std::string& resp) {
3699 if (requested ==
3700 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3701 {
Lei YU92caa4c2021-02-23 16:59:25 +08003702 addRestartCause(RestartCause::watchdog);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003703 }
3704 else
3705 {
3706 throw std::invalid_argument(
3707 "Unrecognized RestartCause Request");
3708 return 0;
3709 }
3710
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003711 std::string logMsg = "RestartCause requested: " + requested;
3712 phosphor::logging::log<phosphor::logging::level::INFO>(
3713 logMsg.c_str());
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003714 resp = requested;
3715 return 1;
3716 });
3717
Lei YU92caa4c2021-02-23 16:59:25 +08003718 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003719
Lei YU92caa4c2021-02-23 16:59:25 +08003720 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003721
Lei YU92caa4c2021-02-23 16:59:25 +08003722 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003723
3724 return 0;
3725}