blob: 4dd7102feedd2e6b10662e65a5d38e7709ce94b9 [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 {
1795 setPowerState(PowerState::waitForSIOPowerGood);
1796 }
1797 else
1798 {
1799 setPowerState(PowerState::on);
1800 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001801 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301802 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001803 case Event::sioS5DeAssert:
1804 setPowerState(PowerState::waitForPSPowerOK);
1805 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001806 case Event::sioPowerGoodAssert:
1807 setPowerState(PowerState::on);
1808 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001809 case Event::powerButtonPressed:
1810 psPowerOKWatchdogTimerStart();
1811 setPowerState(PowerState::waitForPSPowerOK);
1812 break;
1813 case Event::powerOnRequest:
1814 psPowerOKWatchdogTimerStart();
1815 setPowerState(PowerState::waitForPSPowerOK);
1816 powerOn();
1817 break;
1818 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001819 phosphor::logging::log<phosphor::logging::level::INFO>(
1820 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001821 break;
1822 }
1823}
1824
1825static void powerStateTransitionToOff(const Event event)
1826{
1827 logEvent(__FUNCTION__, event);
1828 switch (event)
1829 {
1830 case Event::psPowerOKDeAssert:
1831 // Cancel any GPIO assertions held during the transition
1832 gpioAssertTimer.cancel();
1833 setPowerState(PowerState::off);
1834 break;
1835 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001836 phosphor::logging::log<phosphor::logging::level::INFO>(
1837 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001838 break;
1839 }
1840}
1841
1842static void powerStateGracefulTransitionToOff(const Event event)
1843{
1844 logEvent(__FUNCTION__, event);
1845 switch (event)
1846 {
1847 case Event::psPowerOKDeAssert:
1848 gracefulPowerOffTimer.cancel();
1849 setPowerState(PowerState::off);
1850 break;
1851 case Event::gracefulPowerOffTimerExpired:
1852 setPowerState(PowerState::on);
1853 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001854 case Event::powerOffRequest:
1855 gracefulPowerOffTimer.cancel();
1856 setPowerState(PowerState::transitionToOff);
1857 forcePowerOff();
1858 break;
1859 case Event::powerCycleRequest:
1860 gracefulPowerOffTimer.cancel();
1861 setPowerState(PowerState::transitionToCycleOff);
1862 forcePowerOff();
1863 break;
1864 case Event::resetRequest:
1865 gracefulPowerOffTimer.cancel();
1866 setPowerState(PowerState::on);
1867 reset();
1868 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001869 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001870 phosphor::logging::log<phosphor::logging::level::INFO>(
1871 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001872 break;
1873 }
1874}
1875
1876static void powerStateCycleOff(const Event event)
1877{
1878 logEvent(__FUNCTION__, event);
1879 switch (event)
1880 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001881 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301882 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001883 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301884 if (sioEnabled == true)
1885 {
1886 setPowerState(PowerState::waitForSIOPowerGood);
1887 }
1888 else
1889 {
1890 setPowerState(PowerState::on);
1891 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001892 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301893 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001894 case Event::sioS5DeAssert:
1895 powerCycleTimer.cancel();
1896 setPowerState(PowerState::waitForPSPowerOK);
1897 break;
1898 case Event::powerButtonPressed:
1899 powerCycleTimer.cancel();
1900 psPowerOKWatchdogTimerStart();
1901 setPowerState(PowerState::waitForPSPowerOK);
1902 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001903 case Event::powerCycleTimerExpired:
1904 psPowerOKWatchdogTimerStart();
1905 setPowerState(PowerState::waitForPSPowerOK);
1906 powerOn();
1907 break;
1908 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001909 phosphor::logging::log<phosphor::logging::level::INFO>(
1910 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001911 break;
1912 }
1913}
1914
1915static void powerStateTransitionToCycleOff(const Event event)
1916{
1917 logEvent(__FUNCTION__, event);
1918 switch (event)
1919 {
1920 case Event::psPowerOKDeAssert:
1921 // Cancel any GPIO assertions held during the transition
1922 gpioAssertTimer.cancel();
1923 setPowerState(PowerState::cycleOff);
1924 powerCycleTimerStart();
1925 break;
1926 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001927 phosphor::logging::log<phosphor::logging::level::INFO>(
1928 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001929 break;
1930 }
1931}
1932
1933static void powerStateGracefulTransitionToCycleOff(const Event event)
1934{
1935 logEvent(__FUNCTION__, event);
1936 switch (event)
1937 {
1938 case Event::psPowerOKDeAssert:
1939 gracefulPowerOffTimer.cancel();
1940 setPowerState(PowerState::cycleOff);
1941 powerCycleTimerStart();
1942 break;
1943 case Event::gracefulPowerOffTimerExpired:
1944 setPowerState(PowerState::on);
1945 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001946 case Event::powerOffRequest:
1947 gracefulPowerOffTimer.cancel();
1948 setPowerState(PowerState::transitionToOff);
1949 forcePowerOff();
1950 break;
1951 case Event::powerCycleRequest:
1952 gracefulPowerOffTimer.cancel();
1953 setPowerState(PowerState::transitionToCycleOff);
1954 forcePowerOff();
1955 break;
1956 case Event::resetRequest:
1957 gracefulPowerOffTimer.cancel();
1958 setPowerState(PowerState::on);
1959 reset();
1960 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001961 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001962 phosphor::logging::log<phosphor::logging::level::INFO>(
1963 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001964 break;
1965 }
1966}
1967
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001968static void powerStateCheckForWarmReset(const Event event)
1969{
1970 logEvent(__FUNCTION__, event);
1971 switch (event)
1972 {
1973 case Event::sioS5Assert:
1974 warmResetCheckTimer.cancel();
1975 setPowerState(PowerState::transitionToOff);
1976 break;
1977 case Event::warmResetDetected:
1978 setPowerState(PowerState::on);
1979 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001980 case Event::psPowerOKDeAssert:
1981 warmResetCheckTimer.cancel();
1982 setPowerState(PowerState::off);
1983 // DC power is unexpectedly lost, beep
1984 beep(beepPowerFail);
1985 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001986 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001987 phosphor::logging::log<phosphor::logging::level::INFO>(
1988 "No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001989 break;
1990 }
1991}
1992
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001993static void psPowerOKHandler()
1994{
1995 gpiod::line_event gpioLineEvent = psPowerOKLine.event_read();
1996
1997 Event powerControlEvent =
1998 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
1999 ? Event::psPowerOKAssert
2000 : Event::psPowerOKDeAssert;
2001
2002 sendPowerControlEvent(powerControlEvent);
2003 psPowerOKEvent.async_wait(
2004 boost::asio::posix::stream_descriptor::wait_read,
2005 [](const boost::system::error_code ec) {
2006 if (ec)
2007 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002008 std::string errMsg =
2009 "power supply power OK handler error: " + ec.message();
2010 phosphor::logging::log<phosphor::logging::level::ERR>(
2011 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002012 return;
2013 }
2014 psPowerOKHandler();
2015 });
2016}
2017
2018static void sioPowerGoodHandler()
2019{
2020 gpiod::line_event gpioLineEvent = sioPowerGoodLine.event_read();
2021
2022 Event powerControlEvent =
2023 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
2024 ? Event::sioPowerGoodAssert
2025 : Event::sioPowerGoodDeAssert;
2026
2027 sendPowerControlEvent(powerControlEvent);
2028 sioPowerGoodEvent.async_wait(
2029 boost::asio::posix::stream_descriptor::wait_read,
2030 [](const boost::system::error_code ec) {
2031 if (ec)
2032 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002033 std::string errMsg =
2034 "SIO power good handler error: " + ec.message();
2035 phosphor::logging::log<phosphor::logging::level::ERR>(
2036 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002037 return;
2038 }
2039 sioPowerGoodHandler();
2040 });
2041}
2042
2043static void sioOnControlHandler()
2044{
2045 gpiod::line_event gpioLineEvent = sioOnControlLine.event_read();
2046
2047 bool sioOnControl =
2048 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE;
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002049 std::string logMsg =
2050 "SIO_ONCONTROL value changed: " + std::to_string(sioOnControl);
2051 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002052 sioOnControlEvent.async_wait(
2053 boost::asio::posix::stream_descriptor::wait_read,
2054 [](const boost::system::error_code ec) {
2055 if (ec)
2056 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002057 std::string errMsg =
2058 "SIO ONCONTROL handler error: " + ec.message();
2059 phosphor::logging::log<phosphor::logging::level::ERR>(
2060 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002061 return;
2062 }
2063 sioOnControlHandler();
2064 });
2065}
2066
2067static void sioS5Handler()
2068{
2069 gpiod::line_event gpioLineEvent = sioS5Line.event_read();
2070
2071 Event powerControlEvent =
2072 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE
2073 ? Event::sioS5Assert
2074 : Event::sioS5DeAssert;
2075
2076 sendPowerControlEvent(powerControlEvent);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002077 sioS5Event.async_wait(
2078 boost::asio::posix::stream_descriptor::wait_read,
2079 [](const boost::system::error_code ec) {
2080 if (ec)
2081 {
2082 std::string errMsg = "SIO S5 handler error: " + ec.message();
2083 phosphor::logging::log<phosphor::logging::level::ERR>(
2084 errMsg.c_str());
2085 return;
2086 }
2087 sioS5Handler();
2088 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002089}
2090
2091static void powerButtonHandler()
2092{
2093 gpiod::line_event gpioLineEvent = powerButtonLine.event_read();
2094
2095 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2096 {
2097 powerButtonPressLog();
2098 powerButtonIface->set_property("ButtonPressed", true);
2099 if (!powerButtonMask)
2100 {
2101 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002102 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002103 }
2104 else
2105 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002106 phosphor::logging::log<phosphor::logging::level::INFO>(
2107 "power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002108 }
2109 }
2110 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2111 {
2112 powerButtonIface->set_property("ButtonPressed", false);
2113 }
2114 powerButtonEvent.async_wait(
2115 boost::asio::posix::stream_descriptor::wait_read,
2116 [](const boost::system::error_code ec) {
2117 if (ec)
2118 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002119 std::string errMsg =
2120 "power button handler error: " + ec.message();
2121 phosphor::logging::log<phosphor::logging::level::ERR>(
2122 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002123 return;
2124 }
2125 powerButtonHandler();
2126 });
2127}
2128
2129static void resetButtonHandler()
2130{
2131 gpiod::line_event gpioLineEvent = resetButtonLine.event_read();
2132
2133 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2134 {
2135 resetButtonPressLog();
2136 resetButtonIface->set_property("ButtonPressed", true);
2137 if (!resetButtonMask)
2138 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002139 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002140 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002141 }
2142 else
2143 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002144 phosphor::logging::log<phosphor::logging::level::INFO>(
2145 "reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002146 }
2147 }
2148 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2149 {
2150 resetButtonIface->set_property("ButtonPressed", false);
2151 }
2152 resetButtonEvent.async_wait(
2153 boost::asio::posix::stream_descriptor::wait_read,
2154 [](const boost::system::error_code ec) {
2155 if (ec)
2156 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002157 std::string errMsg =
2158 "reset button handler error: " + ec.message();
2159 phosphor::logging::log<phosphor::logging::level::ERR>(
2160 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002161 return;
2162 }
2163 resetButtonHandler();
2164 });
2165}
2166
Vijay Khemka04175c22020-10-09 14:28:11 -07002167#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002168static constexpr auto systemdBusname = "org.freedesktop.systemd1";
2169static constexpr auto systemdPath = "/org/freedesktop/systemd1";
2170static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
2171static constexpr auto systemTargetName = "chassis-system-reset.target";
2172
2173void systemReset()
2174{
2175 conn->async_method_call(
2176 [](boost::system::error_code ec) {
2177 if (ec)
2178 {
2179 phosphor::logging::log<phosphor::logging::level::ERR>(
2180 "Failed to call chassis system reset",
2181 phosphor::logging::entry("ERR=%s", ec.message().c_str()));
2182 }
2183 },
2184 systemdBusname, systemdPath, systemdInterface, "StartUnit",
2185 systemTargetName, "replace");
2186}
Vijay Khemka04175c22020-10-09 14:28:11 -07002187#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002188
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002189static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002190{
2191 conn->async_method_call(
2192 [](boost::system::error_code ec) {
2193 if (ec)
2194 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002195 phosphor::logging::log<phosphor::logging::level::INFO>(
2196 "failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002197 }
2198 },
Chen Yugang303bd582019-11-01 08:45:06 +08002199 "xyz.openbmc_project.Settings",
2200 "/xyz/openbmc_project/Chassis/Control/NMISource",
2201 "org.freedesktop.DBus.Properties", "Set",
2202 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
2203 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002204}
2205
2206static void nmiReset(void)
2207{
2208 static constexpr const uint8_t value = 1;
2209 const static constexpr int nmiOutPulseTimeMs = 200;
2210
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002211 phosphor::logging::log<phosphor::logging::level::INFO>("NMI out action");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002212 nmiOutLine.set_value(value);
Priyatharshan P70120512020-09-16 18:47:20 +05302213 std::string logMsg =
2214 nmiOutConfig.lineName + " set to " + std::to_string(value);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002215 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002216 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2217 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2218 // restore the NMI_OUT GPIO line back to the opposite value
2219 nmiOutLine.set_value(!value);
Priyatharshan P70120512020-09-16 18:47:20 +05302220 std::string logMsg = nmiOutConfig.lineName + " released";
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002221 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002222 if (ec)
2223 {
2224 // operation_aborted is expected if timer is canceled before
2225 // completion.
2226 if (ec != boost::asio::error::operation_aborted)
2227 {
Priyatharshan P70120512020-09-16 18:47:20 +05302228 std::string errMsg = nmiOutConfig.lineName +
2229 " async_wait failed: " + ec.message();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002230 phosphor::logging::log<phosphor::logging::level::ERR>(
2231 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002232 }
2233 }
2234 });
2235 // log to redfish
2236 nmiDiagIntLog();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002237 phosphor::logging::log<phosphor::logging::level::INFO>(
2238 "NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002239 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002240 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002241}
2242
2243static void nmiSourcePropertyMonitor(void)
2244{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002245 phosphor::logging::log<phosphor::logging::level::INFO>(
2246 "NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002247
2248 static std::unique_ptr<sdbusplus::bus::match::match> nmiSourceMatch =
2249 std::make_unique<sdbusplus::bus::match::match>(
2250 *conn,
2251 "type='signal',interface='org.freedesktop.DBus.Properties',"
Chen Yugang303bd582019-11-01 08:45:06 +08002252 "member='PropertiesChanged',arg0namespace='xyz.openbmc_project."
2253 "Chassis.Control."
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002254 "NMISource'",
2255 [](sdbusplus::message::message& msg) {
2256 std::string interfaceName;
2257 boost::container::flat_map<std::string,
2258 std::variant<bool, std::string>>
2259 propertiesChanged;
2260 std::string state;
2261 bool value = true;
2262 try
2263 {
2264 msg.read(interfaceName, propertiesChanged);
2265 if (propertiesChanged.begin()->first == "Enabled")
2266 {
2267 value =
2268 std::get<bool>(propertiesChanged.begin()->second);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002269 std::string logMsg =
2270 " NMI Enabled propertiesChanged value: " +
2271 std::to_string(value);
2272 phosphor::logging::log<phosphor::logging::level::INFO>(
2273 logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002274 nmiEnabled = value;
2275 if (nmiEnabled)
2276 {
2277 nmiReset();
2278 }
2279 }
2280 }
2281 catch (std::exception& e)
2282 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002283 phosphor::logging::log<phosphor::logging::level::ERR>(
2284 "Unable to read NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002285 return;
2286 }
2287 });
2288}
2289
2290static void setNmiSource()
2291{
2292 conn->async_method_call(
2293 [](boost::system::error_code ec) {
2294 if (ec)
2295 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002296 phosphor::logging::log<phosphor::logging::level::ERR>(
2297 "failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002298 }
2299 },
Chen Yugang303bd582019-11-01 08:45:06 +08002300 "xyz.openbmc_project.Settings",
2301 "/xyz/openbmc_project/Chassis/Control/NMISource",
2302 "org.freedesktop.DBus.Properties", "Set",
2303 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
2304 std::variant<std::string>{"xyz.openbmc_project.Chassis.Control."
2305 "NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002306 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002307 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002308}
2309
2310static void nmiButtonHandler()
2311{
2312 gpiod::line_event gpioLineEvent = nmiButtonLine.event_read();
2313
2314 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2315 {
2316 nmiButtonPressLog();
2317 nmiButtonIface->set_property("ButtonPressed", true);
2318 if (nmiButtonMasked)
2319 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002320 phosphor::logging::log<phosphor::logging::level::INFO>(
2321 "NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002322 }
2323 else
2324 {
2325 setNmiSource();
2326 }
2327 }
2328 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2329 {
2330 nmiButtonIface->set_property("ButtonPressed", false);
2331 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002332 nmiButtonEvent.async_wait(
2333 boost::asio::posix::stream_descriptor::wait_read,
2334 [](const boost::system::error_code ec) {
2335 if (ec)
2336 {
2337 std::string errMsg =
2338 "NMI button handler error: " + ec.message();
2339 phosphor::logging::log<phosphor::logging::level::ERR>(
2340 errMsg.c_str());
2341 return;
2342 }
2343 nmiButtonHandler();
2344 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002345}
2346
2347static void idButtonHandler()
2348{
2349 gpiod::line_event gpioLineEvent = idButtonLine.event_read();
2350
2351 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2352 {
2353 idButtonIface->set_property("ButtonPressed", true);
2354 }
2355 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2356 {
2357 idButtonIface->set_property("ButtonPressed", false);
2358 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002359 idButtonEvent.async_wait(
2360 boost::asio::posix::stream_descriptor::wait_read,
2361 [](const boost::system::error_code& ec) {
2362 if (ec)
2363 {
2364 std::string errMsg = "ID button handler error: " + ec.message();
2365 phosphor::logging::log<phosphor::logging::level::ERR>(
2366 errMsg.c_str());
2367 return;
2368 }
2369 idButtonHandler();
2370 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002371}
2372
Jason M. Billsfb957332021-01-28 13:18:46 -08002373static void pltRstHandler(bool pltRst)
2374{
2375 if (pltRst)
2376 {
2377 sendPowerControlEvent(Event::pltRstDeAssert);
2378 }
2379 else
2380 {
2381 sendPowerControlEvent(Event::pltRstAssert);
2382 }
2383}
2384
2385static void hostMiscHandler(sdbusplus::message::message& msg)
2386{
2387 std::string interfaceName;
2388 boost::container::flat_map<std::string, std::variant<bool>>
2389 propertiesChanged;
2390 bool pltRst;
2391 try
2392 {
2393 msg.read(interfaceName, propertiesChanged);
2394 }
2395 catch (std::exception& e)
2396 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002397 phosphor::logging::log<phosphor::logging::level::ERR>(
2398 "Unable to read Host Misc status");
Jason M. Billsfb957332021-01-28 13:18:46 -08002399 return;
2400 }
2401 if (propertiesChanged.empty())
2402 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002403 phosphor::logging::log<phosphor::logging::level::ERR>(
2404 "ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002405 return;
2406 }
2407
2408 for (auto& [property, value] : propertiesChanged)
2409 {
2410 if (property == "ESpiPlatformReset")
2411 {
2412 bool* pltRst = std::get_if<bool>(&value);
2413 if (pltRst == nullptr)
2414 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002415 std::string errMsg = property + " property invalid";
2416 phosphor::logging::log<phosphor::logging::level::ERR>(
2417 errMsg.c_str());
Jason M. Billsfb957332021-01-28 13:18:46 -08002418 return;
2419 }
2420 pltRstHandler(*pltRst);
2421 }
2422 }
2423}
2424
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002425static void postCompleteHandler()
2426{
2427 gpiod::line_event gpioLineEvent = postCompleteLine.event_read();
2428
2429 bool postComplete =
2430 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002431 if (postComplete)
2432 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002433 sendPowerControlEvent(Event::postCompleteAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002434 osIface->set_property("OperatingSystemState", std::string("Standby"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002435 }
2436 else
2437 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002438 sendPowerControlEvent(Event::postCompleteDeAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002439 osIface->set_property("OperatingSystemState", std::string("Inactive"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002440 }
2441 postCompleteEvent.async_wait(
2442 boost::asio::posix::stream_descriptor::wait_read,
2443 [](const boost::system::error_code ec) {
2444 if (ec)
2445 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002446 std::string errMsg =
2447 "POST complete handler error: " + ec.message();
2448 phosphor::logging::log<phosphor::logging::level::ERR>(
2449 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002450 return;
2451 }
2452 postCompleteHandler();
2453 });
2454}
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302455
2456static int loadConfigValues()
2457{
2458 const std::string configFilePath =
2459 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2460 ".json";
2461 std::ifstream configFile(configFilePath.c_str());
2462 if (!configFile.is_open())
2463 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002464 phosphor::logging::log<phosphor::logging::level::ERR>(
2465 "loadConfigValues : Cannot open config path");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302466 return -1;
2467 }
Zev Weiss1aa08b22021-09-15 17:06:20 -05002468 auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302469
Priyatharshan P70120512020-09-16 18:47:20 +05302470 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302471 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002472 phosphor::logging::log<phosphor::logging::level::ERR>(
2473 "Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302474 return -1;
2475 }
Priyatharshan P70120512020-09-16 18:47:20 +05302476 auto gpios = jsonData["gpio_configs"];
2477 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302478
Priyatharshan P70120512020-09-16 18:47:20 +05302479 ConfigData* tempGpioData;
2480
2481 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302482 {
Priyatharshan P70120512020-09-16 18:47:20 +05302483 if (!gpioConfig.contains("Name"))
2484 {
2485 phosphor::logging::log<phosphor::logging::level::ERR>(
2486 "The 'Name' field must be defined in Json file");
2487 return -1;
2488 }
2489
2490 // Iterate through the powersignal map to check if the gpio json config
2491 // entry is valid
2492 std::string gpioName = gpioConfig["Name"];
2493 auto signalMapIter = powerSignalMap.find(gpioName);
2494 if (signalMapIter == powerSignalMap.end())
2495 {
2496 std::string errMsg = "Undefined Name : " + gpioName;
2497 phosphor::logging::log<phosphor::logging::level::ERR>(
2498 errMsg.c_str());
2499 return -1;
2500 }
2501
2502 // assign the power signal name to the corresponding structure reference
2503 // from map then fillup the structure with coressponding json config
2504 // value
2505 tempGpioData = signalMapIter->second;
2506 tempGpioData->name = gpioName;
2507
2508 if (!gpioConfig.contains("Type"))
2509 {
2510 phosphor::logging::log<phosphor::logging::level::ERR>(
2511 "The \'Type\' field must be defined in Json file");
2512 return -1;
2513 }
2514
2515 std::string signalType = gpioConfig["Type"];
2516 if (signalType == "GPIO")
2517 {
2518 tempGpioData->type = ConfigType::GPIO;
2519 }
2520 else if (signalType == "DBUS")
2521 {
2522 tempGpioData->type = ConfigType::DBUS;
2523 }
2524 else
2525 {
2526 std::string errMsg = "Undefined Type : " + signalType;
2527 phosphor::logging::log<phosphor::logging::level::ERR>(
2528 errMsg.c_str());
2529 return -1;
2530 }
2531
2532 if (tempGpioData->type == ConfigType::GPIO)
2533 {
2534 if (gpioConfig.contains("LineName"))
2535 {
2536 tempGpioData->lineName = gpioConfig["LineName"];
2537 }
2538 else
2539 {
2540 phosphor::logging::log<phosphor::logging::level::ERR>(
2541 "The \'LineName\' field must be defined for GPIO "
2542 "configuration");
2543 return -1;
2544 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002545 if (gpioConfig.contains("Polarity"))
2546 {
2547 std::string polarity = gpioConfig["Polarity"];
2548 if (polarity == "ActiveLow")
2549 {
2550 tempGpioData->polarity = false;
2551 }
2552 else if (polarity == "ActiveHigh")
2553 {
2554 tempGpioData->polarity = true;
2555 }
2556 else
2557 {
2558 std::string errMsg =
2559 "Polarity defined but not properly setup. Please "
2560 "only ActiveHigh or ActiveLow. Currently set to " +
2561 polarity;
2562 phosphor::logging::log<phosphor::logging::level::ERR>(
2563 errMsg.c_str());
2564 return -1;
2565 }
2566 }
2567 else
2568 {
2569 std::string errMsg =
2570 "Polarity field not found for " + tempGpioData->lineName;
2571 phosphor::logging::log<phosphor::logging::level::ERR>(
2572 errMsg.c_str());
2573 return -1;
2574 }
Priyatharshan P70120512020-09-16 18:47:20 +05302575 }
2576 else
2577 {
2578 // if dbus based gpio config is defined read and update the dbus
2579 // params corresponding to the gpio config instance
2580 for (auto& [key, dbusParamName] : dbusParams)
2581 {
2582 if (!gpios.contains(dbusParamName))
2583 {
2584 std::string errMsg =
2585 "The " + dbusParamName +
2586 "field must be defined for Dbus configuration ";
2587 phosphor::logging::log<phosphor::logging::level::ERR>(
2588 errMsg.c_str());
2589 return -1;
2590 }
2591 }
2592 tempGpioData->dbusName = gpios[dbusParams[DbusConfigType::name]];
2593 tempGpioData->path = gpios[dbusParams[DbusConfigType::path]];
2594 tempGpioData->interface =
2595 gpios[dbusParams[DbusConfigType::interface]];
2596 tempGpioData->lineName =
2597 gpios[dbusParams[DbusConfigType::property]];
2598 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302599 }
2600
Priyatharshan P70120512020-09-16 18:47:20 +05302601 // read and store the timer values from json config to Timer Map
2602 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302603 {
Priyatharshan P70120512020-09-16 18:47:20 +05302604 if (timers.contains(key.c_str()))
2605 {
2606 timerValue = timers[key.c_str()];
2607 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302608 }
2609
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302610 return 0;
2611}
Priyatharshan P70120512020-09-16 18:47:20 +05302612inline static sdbusplus::bus::match::match powerButtonEventMonitor()
2613{
2614 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2615 bool value = false;
2616 std::string thresholdInterface;
2617 std::string event;
2618 boost::container::flat_map<std::string, std::variant<bool>>
2619 propertiesChanged;
2620 try
2621 {
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302622
Priyatharshan P70120512020-09-16 18:47:20 +05302623 msg.read(thresholdInterface, propertiesChanged);
2624
2625 if (propertiesChanged.empty())
2626 {
2627 return;
2628 }
2629 event = propertiesChanged.begin()->first;
2630
2631 if (event.empty() || event != powerButtonConfig.lineName)
2632 {
2633 return;
2634 }
2635
2636 value = std::get<bool>(propertiesChanged.begin()->second);
2637 }
2638 catch (std::exception& e)
2639 {
2640 phosphor::logging::log<phosphor::logging::level::ERR>(
2641 "exception during reading dbus property : powerButtonConfig");
2642 return;
2643 }
2644
2645 if (value == false)
2646 {
2647 powerButtonPressLog();
2648 powerButtonIface->set_property("ButtonPressed", true);
2649 if (!powerButtonMask)
2650 {
2651 sendPowerControlEvent(Event::powerButtonPressed);
2652 addRestartCause(RestartCause::powerButton);
2653 }
2654 else
2655 {
2656 phosphor::logging::log<phosphor::logging::level::ERR>(
2657 "power button press masked\n");
2658 }
2659 }
2660 else
2661 {
2662 powerButtonIface->set_property("ButtonPressed", false);
2663 }
2664 };
2665
2666 sdbusplus::bus::match::match pulseEventMatcher(
2667 static_cast<sdbusplus::bus::bus&>(*conn),
2668 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2669 "PropertiesChanged',arg0='" +
2670 powerButtonConfig.dbusName + "'",
2671 std::move(pulseEventMatcherCallback));
2672
2673 return pulseEventMatcher;
2674}
2675
2676inline static sdbusplus::bus::match::match resetButtonEventMonitor()
2677{
2678 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2679 bool value = false;
2680 std::string thresholdInterface;
2681 std::string event;
2682 boost::container::flat_map<std::string, std::variant<bool>>
2683 propertiesChanged;
2684 try
2685 {
2686 msg.read(thresholdInterface, propertiesChanged);
2687
2688 if (propertiesChanged.empty())
2689 {
2690 return;
2691 }
2692 event = propertiesChanged.begin()->first;
2693
2694 if (event.empty() || event != resetButtonConfig.lineName)
2695 {
2696 return;
2697 }
2698
2699 value = std::get<bool>(propertiesChanged.begin()->second);
2700 }
2701 catch (std::exception& e)
2702 {
2703 phosphor::logging::log<phosphor::logging::level::ERR>(
2704 "exception during reading dbus property : resetButtonConfig");
2705 return;
2706 }
2707
2708 if (value == false)
2709 {
2710 resetButtonPressLog();
2711 resetButtonIface->set_property("ButtonPressed", true);
2712 if (!resetButtonMask)
2713 {
2714 sendPowerControlEvent(Event::resetButtonPressed);
2715 addRestartCause(RestartCause::resetButton);
2716 }
2717 else
2718 {
2719 phosphor::logging::log<phosphor::logging::level::ERR>(
2720 "reset button press masked");
2721 }
2722 }
2723 else
2724 {
2725 resetButtonIface->set_property("ButtonPressed", false);
2726 }
2727 };
2728
2729 sdbusplus::bus::match::match pulseEventMatcher(
2730 static_cast<sdbusplus::bus::bus&>(*conn),
2731 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2732 "PropertiesChanged',arg0='" +
2733 resetButtonConfig.dbusName + "'",
2734 std::move(pulseEventMatcherCallback));
2735
2736 return pulseEventMatcher;
2737}
2738
2739inline static sdbusplus::bus::match::match powerOkEventMonitor()
2740{
2741 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2742 bool value = false;
2743 std::string thresholdInterface;
2744 std::string event;
2745 boost::container::flat_map<std::string, std::variant<bool>>
2746 propertiesChanged;
2747 try
2748 {
2749 msg.read(thresholdInterface, propertiesChanged);
2750
2751 if (propertiesChanged.empty())
2752 {
2753 return;
2754 }
2755 event = propertiesChanged.begin()->first;
2756
2757 if (event.empty() || event != powerOkConfig.lineName)
2758 {
2759 return;
2760 }
2761
2762 value = std::get<bool>(propertiesChanged.begin()->second);
2763 }
2764 catch (std::exception& e)
2765 {
2766 phosphor::logging::log<phosphor::logging::level::ERR>(
2767 "exception during reading dbus property : powerOkConfig");
2768 return;
2769 }
2770
2771 Event powerControlEvent =
2772 value ? Event::psPowerOKAssert : Event::psPowerOKDeAssert;
2773 sendPowerControlEvent(powerControlEvent);
2774 };
2775
2776 sdbusplus::bus::match::match pulseEventMatcher(
2777 static_cast<sdbusplus::bus::bus&>(*conn),
2778 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2779 "PropertiesChanged',arg0='" +
2780 powerOkConfig.dbusName + "'",
2781 std::move(pulseEventMatcherCallback));
2782
2783 return pulseEventMatcher;
2784}
2785
2786inline static sdbusplus::bus::match::match sioPwrGoodEventMonitor()
2787{
2788 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2789 bool value = false;
2790 std::string thresholdInterface;
2791 std::string event;
2792 boost::container::flat_map<std::string, std::variant<bool>>
2793 propertiesChanged;
2794 try
2795 {
2796 msg.read(thresholdInterface, propertiesChanged);
2797
2798 if (propertiesChanged.empty())
2799 {
2800 return;
2801 }
2802 event = propertiesChanged.begin()->first;
2803
2804 if (event.empty() || event != sioPwrGoodConfig.lineName)
2805 {
2806 return;
2807 }
2808
2809 value = std::get<bool>(propertiesChanged.begin()->second);
2810 }
2811 catch (std::exception& e)
2812 {
2813 phosphor::logging::log<phosphor::logging::level::ERR>(
2814 "exception during reading dbus property : sioPwrGoodConfig");
2815 return;
2816 }
2817
2818 Event powerControlEvent =
2819 value ? Event::sioPowerGoodAssert : Event::sioPowerGoodDeAssert;
2820
2821 sendPowerControlEvent(powerControlEvent);
2822 };
2823
2824 sdbusplus::bus::match::match pulseEventMatcher(
2825 static_cast<sdbusplus::bus::bus&>(*conn),
2826 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2827 "PropertiesChanged',arg0='" +
2828 sioPwrGoodConfig.dbusName + "'",
2829 std::move(pulseEventMatcherCallback));
2830
2831 return pulseEventMatcher;
2832}
2833
2834inline static sdbusplus::bus::match::match sioOnControlEventMonitor()
2835{
2836 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2837 bool value = false;
2838 std::string thresholdInterface;
2839 std::string event;
2840 boost::container::flat_map<std::string, std::variant<bool>>
2841 propertiesChanged;
2842 try
2843 {
2844 msg.read(thresholdInterface, propertiesChanged);
2845
2846 if (propertiesChanged.empty())
2847 {
2848 return;
2849 }
2850 event = propertiesChanged.begin()->first;
2851
2852 if (event.empty() || event != sioOnControlConfig.lineName)
2853 {
2854 return;
2855 }
2856
2857 value = std::get<bool>(propertiesChanged.begin()->second);
2858 }
2859 catch (std::exception& e)
2860 {
2861 phosphor::logging::log<phosphor::logging::level::ERR>(
2862 "exception during reading dbus property : sioOnControlConfig");
2863 return;
2864 }
2865
2866 std::string errMsg =
2867 "SIO_ONCONTROL value changed : " + std::to_string(value);
2868 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
2869 };
2870
2871 sdbusplus::bus::match::match pulseEventMatcher(
2872 static_cast<sdbusplus::bus::bus&>(*conn),
2873 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2874 "PropertiesChanged',arg0='" +
2875 sioOnControlConfig.dbusName + "'",
2876 std::move(pulseEventMatcherCallback));
2877
2878 return pulseEventMatcher;
2879}
2880
2881inline static sdbusplus::bus::match::match sioS5EventMonitor()
2882{
2883 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2884 bool value = false;
2885 std::string thresholdInterface;
2886 std::string event;
2887 boost::container::flat_map<std::string, std::variant<bool>>
2888 propertiesChanged;
2889 try
2890 {
2891 msg.read(thresholdInterface, propertiesChanged);
2892
2893 if (propertiesChanged.empty())
2894 {
2895 return;
2896 }
2897 event = propertiesChanged.begin()->first;
2898
2899 if (event.empty() || event != sioS5Config.lineName)
2900 {
2901 return;
2902 }
2903
2904 value = std::get<bool>(propertiesChanged.begin()->second);
2905 }
2906 catch (std::exception& e)
2907 {
2908 phosphor::logging::log<phosphor::logging::level::ERR>(
2909 "exception during reading dbus property : sioS5Config");
2910 return;
2911 }
2912
2913 Event powerControlEvent =
2914 value ? Event::sioS5DeAssert : Event::sioS5Assert;
2915 sendPowerControlEvent(powerControlEvent);
2916 };
2917
2918 sdbusplus::bus::match::match pulseEventMatcher(
2919 static_cast<sdbusplus::bus::bus&>(*conn),
2920 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2921 "PropertiesChanged',arg0='" +
2922 sioS5Config.dbusName + "'",
2923 std::move(pulseEventMatcherCallback));
2924
2925 return pulseEventMatcher;
2926}
2927
2928inline static sdbusplus::bus::match::match nmiButtonEventMonitor()
2929{
2930 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2931 bool value = false;
2932 std::string thresholdInterface;
2933 std::string event;
2934 boost::container::flat_map<std::string, std::variant<bool>>
2935 propertiesChanged;
2936 try
2937 {
2938 msg.read(thresholdInterface, propertiesChanged);
2939
2940 if (propertiesChanged.empty())
2941 {
2942 return;
2943 }
2944 event = propertiesChanged.begin()->first;
2945 if (event.empty() || event != nmiButtonConfig.lineName)
2946 {
2947 return;
2948 }
2949
2950 value = std::get<bool>(propertiesChanged.begin()->second);
2951 }
2952 catch (std::exception& e)
2953 {
2954 phosphor::logging::log<phosphor::logging::level::ERR>(
2955 "exception during reading dbus property : nmiButtonConfig");
2956 return;
2957 }
2958
2959 if (value)
2960 {
2961 nmiButtonIface->set_property("ButtonPressed", false);
2962 }
2963 else
2964 {
2965 nmiButtonPressLog();
2966 nmiButtonIface->set_property("ButtonPressed", true);
2967 if (nmiButtonMasked)
2968 {
2969 phosphor::logging::log<phosphor::logging::level::ERR>(
2970 "NMI button press masked");
2971 }
2972 else
2973 {
2974 setNmiSource();
2975 }
2976 }
2977 };
2978
2979 sdbusplus::bus::match::match pulseEventMatcher(
2980 static_cast<sdbusplus::bus::bus&>(*conn),
2981 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2982 "PropertiesChanged',arg0='" +
2983 nmiButtonConfig.dbusName + "'",
2984 std::move(pulseEventMatcherCallback));
2985
2986 return pulseEventMatcher;
2987}
2988
2989inline static sdbusplus::bus::match::match idButtonEventMonitor()
2990{
2991 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2992 bool value = false;
2993 std::string thresholdInterface;
2994 std::string event;
2995 boost::container::flat_map<std::string, std::variant<bool>>
2996 propertiesChanged;
2997
2998 try
2999 {
3000
3001 msg.read(thresholdInterface, propertiesChanged);
3002
3003 if (propertiesChanged.empty())
3004 {
3005 return;
3006 }
3007 event = propertiesChanged.begin()->first;
3008
3009 if (event.empty() | event != idButtonConfig.lineName)
3010 {
3011 return;
3012 }
3013
3014 value = std::get<bool>(propertiesChanged.begin()->second);
3015 }
3016 catch (std::exception& e)
3017 {
3018 phosphor::logging::log<phosphor::logging::level::ERR>(
3019 "exception during reading dbus property : idButtonConfig");
3020 return;
3021 }
3022
3023 if (value)
3024 {
3025 idButtonIface->set_property("ButtonPressed", false);
3026 }
3027 else
3028 {
3029 idButtonIface->set_property("ButtonPressed", true);
3030 }
3031 };
3032
3033 sdbusplus::bus::match::match pulseEventMatcher(
3034 static_cast<sdbusplus::bus::bus&>(*conn),
3035 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
3036 "PropertiesChanged',arg0='" +
3037 idButtonConfig.dbusName + "'",
3038 std::move(pulseEventMatcherCallback));
3039
3040 return pulseEventMatcher;
3041}
3042
3043inline static sdbusplus::bus::match::match postCompleteEventMonitor()
3044{
3045 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
3046 bool value = false;
3047 std::string thresholdInterface;
3048 std::string event;
3049 boost::container::flat_map<std::string, std::variant<bool>>
3050 propertiesChanged;
3051 try
3052 {
3053
3054 msg.read(thresholdInterface, propertiesChanged);
3055
3056 if (propertiesChanged.empty())
3057 {
3058 return;
3059 }
3060 event = propertiesChanged.begin()->first;
3061
3062 if (event.empty() | event != postCompleteConfig.lineName)
3063 {
3064 return;
3065 }
3066
3067 value = std::get<bool>(propertiesChanged.begin()->second);
3068 }
3069 catch (std::exception& e)
3070 {
3071 phosphor::logging::log<phosphor::logging::level::ERR>(
3072 "exception during reading dbus property : postCompleteConfig");
3073 return;
3074 }
3075
3076 if (value)
3077 {
3078 sendPowerControlEvent(Event::postCompleteDeAssert);
3079 osIface->set_property("OperatingSystemState",
3080 std::string("Inactive"));
3081 }
3082 else
3083 {
3084 sendPowerControlEvent(Event::postCompleteAssert);
3085 osIface->set_property("OperatingSystemState",
3086 std::string("Standby"));
3087 }
3088 };
3089
3090 sdbusplus::bus::match::match pulseEventMatcher(
3091 static_cast<sdbusplus::bus::bus&>(*conn),
3092 "type='signal',path='" + postCompleteConfig.path +
3093 "',interface='org.freedesktop.DBus.Properties',member='"
3094 "PropertiesChanged',arg0='" +
3095 postCompleteConfig.dbusName + "'",
3096 std::move(pulseEventMatcherCallback));
3097
3098 return pulseEventMatcher;
3099}
3100
3101int getProperty(ConfigData& configData)
3102{
3103 auto method = conn->new_method_call(
3104 configData.dbusName.c_str(), configData.path.c_str(),
3105 "org.freedesktop.DBus.Properties", "Get");
3106 method.append(configData.interface.c_str(), configData.lineName.c_str());
3107
3108 auto reply = conn->call(method);
3109 if (reply.is_method_error())
3110 {
3111 phosphor::logging::log<phosphor::logging::level::ERR>(
3112 "Error reading from Bus");
3113 return -1;
3114 }
3115 std::variant<int> resp;
3116 reply.read(resp);
3117 auto respValue = std::get_if<int>(&resp);
3118 if (!respValue)
3119 {
3120 phosphor::logging::log<phosphor::logging::level::ERR>(
3121 "Error reading response");
3122 return -1;
3123 }
3124 return (*respValue);
3125}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003126} // namespace power_control
3127
3128int main(int argc, char* argv[])
3129{
Lei YU92caa4c2021-02-23 16:59:25 +08003130 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05303131
3132 if (argc > 1)
3133 {
3134 node = argv[1];
3135 }
3136 std::string infoMsg =
3137 "Start Chassis power control service for host : " + node;
3138 phosphor::logging::log<phosphor::logging::level::INFO>(infoMsg.c_str());
3139
Lei YU92caa4c2021-02-23 16:59:25 +08003140 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003141
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303142 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08003143 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303144 {
Lei YU92caa4c2021-02-23 16:59:25 +08003145 std::string errMsg = "Host" + node + ": " + "Error in Parsing...";
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003146 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303147 }
Naveen Mosesec972d82021-07-16 21:19:23 +05303148 /* Currently for single host based systems additional busname is added
3149 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
3150 Going forward for single hosts the old bus name without zero numbering
3151 will be removed when all other applications adapted to the
3152 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
3153
3154 if (node == "0")
3155 {
3156 // Request all the dbus names
3157 conn->request_name(hostDbusName.c_str());
3158 conn->request_name(chassisDbusName.c_str());
3159 conn->request_name(osDbusName.c_str());
3160 conn->request_name(buttonDbusName.c_str());
3161 conn->request_name(nmiDbusName.c_str());
3162 conn->request_name(rstCauseDbusName.c_str());
3163 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303164
Zev Weissc4005bd2021-09-01 22:30:23 -05003165 hostDbusName += node;
3166 chassisDbusName += node;
3167 osDbusName += node;
3168 buttonDbusName += node;
3169 nmiDbusName += node;
3170 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003171
Priyatharshan P70120512020-09-16 18:47:20 +05303172 // Request all the dbus names
3173 conn->request_name(hostDbusName.c_str());
3174 conn->request_name(chassisDbusName.c_str());
3175 conn->request_name(osDbusName.c_str());
3176 conn->request_name(buttonDbusName.c_str());
3177 conn->request_name(nmiDbusName.c_str());
3178 conn->request_name(rstCauseDbusName.c_str());
3179
3180 if (sioPwrGoodConfig.lineName.empty() ||
3181 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05303182 {
Lei YU92caa4c2021-02-23 16:59:25 +08003183 sioEnabled = false;
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003184 phosphor::logging::log<phosphor::logging::level::INFO>(
3185 "SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05303186 }
3187
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003188 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303189 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003190 {
Priyatharshan P70120512020-09-16 18:47:20 +05303191 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
3192 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303193 {
3194 return -1;
3195 }
3196 }
Priyatharshan P70120512020-09-16 18:47:20 +05303197 else if (powerOkConfig.type == ConfigType::DBUS)
3198 {
3199
3200 static sdbusplus::bus::match::match powerOkEventMonitor =
3201 power_control::powerOkEventMonitor();
3202 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303203 else
3204 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003205 phosphor::logging::log<phosphor::logging::level::ERR>(
3206 "PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003207 return -1;
3208 }
3209
Lei YU92caa4c2021-02-23 16:59:25 +08003210 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003211 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05303212 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303213 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303214 {
Priyatharshan P70120512020-09-16 18:47:20 +05303215 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
3216 sioPowerGoodHandler, sioPowerGoodLine,
3217 sioPowerGoodEvent))
3218 {
3219 return -1;
3220 }
3221 }
3222 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
3223 {
3224 static sdbusplus::bus::match::match sioPwrGoodEventMonitor =
3225 power_control::sioPwrGoodEventMonitor();
3226 }
3227 else
3228 {
3229 phosphor::logging::log<phosphor::logging::level::ERR>(
3230 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303231 return -1;
3232 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003233
Priyatharshan P19c47a32020-08-12 18:16:43 +05303234 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303235 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303236 {
Priyatharshan P70120512020-09-16 18:47:20 +05303237 if (!requestGPIOEvents(sioOnControlConfig.lineName,
3238 sioOnControlHandler, sioOnControlLine,
3239 sioOnControlEvent))
3240 {
3241 return -1;
3242 }
3243 }
3244 else if (sioOnControlConfig.type == ConfigType::DBUS)
3245 {
3246 static sdbusplus::bus::match::match sioOnControlEventMonitor =
3247 power_control::sioOnControlEventMonitor();
3248 }
3249 else
3250 {
3251 phosphor::logging::log<phosphor::logging::level::ERR>(
3252 "sioOnControl name should be configured from json"
3253 "config file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303254 return -1;
3255 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003256
Priyatharshan P19c47a32020-08-12 18:16:43 +05303257 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303258 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303259 {
Priyatharshan P70120512020-09-16 18:47:20 +05303260 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
3261 sioS5Line, sioS5Event))
3262 {
3263 return -1;
3264 }
3265 }
3266 else if (sioS5Config.type == ConfigType::DBUS)
3267 {
3268 static sdbusplus::bus::match::match sioS5EventMonitor =
3269 power_control::sioS5EventMonitor();
3270 }
3271 else
3272 {
3273 phosphor::logging::log<phosphor::logging::level::ERR>(
3274 "sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303275 return -1;
3276 }
3277 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003278
3279 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303280 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003281 {
Priyatharshan P70120512020-09-16 18:47:20 +05303282 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
Lei YU92caa4c2021-02-23 16:59:25 +08003283 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303284 {
3285 return -1;
3286 }
3287 }
Priyatharshan P70120512020-09-16 18:47:20 +05303288 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303289 {
Priyatharshan P70120512020-09-16 18:47:20 +05303290 static sdbusplus::bus::match::match powerButtonEventMonitor =
3291 power_control::powerButtonEventMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003292 }
3293
3294 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303295 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003296 {
Priyatharshan P70120512020-09-16 18:47:20 +05303297 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
Lei YU92caa4c2021-02-23 16:59:25 +08003298 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303299 {
3300 return -1;
3301 }
3302 }
Priyatharshan P70120512020-09-16 18:47:20 +05303303 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303304 {
Priyatharshan P70120512020-09-16 18:47:20 +05303305 static sdbusplus::bus::match::match resetButtonEventMonitor =
3306 power_control::resetButtonEventMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003307 }
3308
3309 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303310 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303311 {
Priyatharshan P70120512020-09-16 18:47:20 +05303312 if (!nmiButtonConfig.lineName.empty())
3313 {
3314 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
3315 nmiButtonLine, nmiButtonEvent);
3316 }
3317 }
3318 else if (nmiButtonConfig.type == ConfigType::DBUS)
3319 {
3320 static sdbusplus::bus::match::match nmiButtonEventMonitor =
3321 power_control::nmiButtonEventMonitor();
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303322 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003323
3324 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303325 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303326 {
Priyatharshan P70120512020-09-16 18:47:20 +05303327 if (!idButtonConfig.lineName.empty())
3328 {
3329 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
3330 idButtonLine, idButtonEvent);
3331 }
3332 }
3333 else if (idButtonConfig.type == ConfigType::DBUS)
3334 {
3335 static sdbusplus::bus::match::match idButtonEventMonitor =
3336 power_control::idButtonEventMonitor();
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303337 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003338
Jason M. Billsfb957332021-01-28 13:18:46 -08003339#ifdef USE_PLT_RST
3340 sdbusplus::bus::match::match pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08003341 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08003342 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
3343 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08003344 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08003345#endif
3346
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003347 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303348 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003349 {
Priyatharshan P70120512020-09-16 18:47:20 +05303350 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
Lei YU92caa4c2021-02-23 16:59:25 +08003351 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303352 {
3353 return -1;
3354 }
3355 }
Priyatharshan P70120512020-09-16 18:47:20 +05303356 else if (postCompleteConfig.type == ConfigType::DBUS)
3357 {
3358 static sdbusplus::bus::match::match postCompleteEventMonitor =
3359 power_control::postCompleteEventMonitor();
3360 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303361 else
3362 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003363 phosphor::logging::log<phosphor::logging::level::ERR>(
3364 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003365 return -1;
3366 }
3367
3368 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05303369 if (!nmiOutConfig.lineName.empty())
3370 {
3371 setGPIOOutput(nmiOutConfig.lineName, 0, nmiOutLine);
3372 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003373
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003374 // Initialize POWER_OUT and RESET_OUT GPIO.
3375 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05303376 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003377 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07003378 if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
3379 line))
Priyatharshan P70120512020-09-16 18:47:20 +05303380 {
3381 return -1;
3382 }
3383 }
3384 else
3385 {
3386 phosphor::logging::log<phosphor::logging::level::ERR>(
3387 "powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003388 return -1;
3389 }
3390
Priyatharshan P70120512020-09-16 18:47:20 +05303391 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003392 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07003393 if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
3394 line))
Priyatharshan P70120512020-09-16 18:47:20 +05303395 {
3396 return -1;
3397 }
3398 }
3399 else
3400 {
3401 phosphor::logging::log<phosphor::logging::level::ERR>(
3402 "ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003403 return -1;
3404 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003405 // Release line
3406 line.reset();
3407
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003408 // Initialize the power state
Lei YU92caa4c2021-02-23 16:59:25 +08003409 powerState = PowerState::off;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003410 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05303411
3412 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003413 {
Priyatharshan P70120512020-09-16 18:47:20 +05303414 if (psPowerOKLine.get_value() > 0)
3415 {
3416 powerState = PowerState::on;
3417 }
3418 }
3419 else
3420 {
3421 if (getProperty(powerOkConfig))
3422 {
3423 powerState = PowerState::on;
3424 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003425 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003426 // Initialize the power state storage
Lei YU92caa4c2021-02-23 16:59:25 +08003427 if (initializePowerStateStorage() < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003428 {
3429 return -1;
3430 }
3431
3432 // Check if we need to start the Power Restore policy
Lei YU92caa4c2021-02-23 16:59:25 +08003433 powerRestorePolicyCheck();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003434
Lei YU92caa4c2021-02-23 16:59:25 +08003435 if (nmiOutLine)
3436 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003437
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003438 phosphor::logging::log<phosphor::logging::level::INFO>(
3439 "Initializing power state. ");
Lei YU92caa4c2021-02-23 16:59:25 +08003440 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003441
3442 // Power Control Service
3443 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003444 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003445
3446 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303447 hostIface =
3448 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
3449 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003450 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08003451 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003452 "RequestedHostTransition",
3453 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
3454 [](const std::string& requested, std::string& resp) {
3455 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
3456 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003457 // if power button is masked, ignore this
3458 if (!powerButtonMask)
3459 {
3460 sendPowerControlEvent(Event::gracefulPowerOffRequest);
3461 addRestartCause(RestartCause::command);
3462 }
3463 else
3464 {
3465 phosphor::logging::log<phosphor::logging::level::INFO>(
3466 "Power Button Masked.");
3467 throw std::invalid_argument("Transition Request Masked");
3468 return 0;
3469 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003470 }
3471 else if (requested ==
3472 "xyz.openbmc_project.State.Host.Transition.On")
3473 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003474 // if power button is masked, ignore this
3475 if (!powerButtonMask)
3476 {
3477 sendPowerControlEvent(Event::powerOnRequest);
3478 addRestartCause(RestartCause::command);
3479 }
3480 else
3481 {
3482 phosphor::logging::log<phosphor::logging::level::INFO>(
3483 "Power Button Masked.");
3484 throw std::invalid_argument("Transition Request Masked");
3485 return 0;
3486 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003487 }
3488 else if (requested ==
3489 "xyz.openbmc_project.State.Host.Transition.Reboot")
3490 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003491 // if power button is masked, ignore this
3492 if (!powerButtonMask)
3493 {
3494 sendPowerControlEvent(Event::powerCycleRequest);
3495 addRestartCause(RestartCause::command);
3496 }
3497 else
3498 {
3499 phosphor::logging::log<phosphor::logging::level::INFO>(
3500 "Power Button Masked.");
3501 throw std::invalid_argument("Transition Request Masked");
3502 return 0;
3503 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003504 }
3505 else if (requested == "xyz.openbmc_project.State.Host.Transition."
3506 "GracefulWarmReboot")
3507 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003508 // if reset button is masked, ignore this
3509 if (!resetButtonMask)
3510 {
3511 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
3512 addRestartCause(RestartCause::command);
3513 }
3514 else
3515 {
3516 phosphor::logging::log<phosphor::logging::level::INFO>(
3517 "Reset Button Masked.");
3518 throw std::invalid_argument("Transition Request Masked");
3519 return 0;
3520 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003521 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003522 else if (requested == "xyz.openbmc_project.State.Host.Transition."
3523 "ForceWarmReboot")
3524 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003525 // if reset button is masked, ignore this
3526 if (!resetButtonMask)
3527 {
3528 sendPowerControlEvent(Event::resetRequest);
3529 addRestartCause(RestartCause::command);
3530 }
3531 else
3532 {
3533 phosphor::logging::log<phosphor::logging::level::INFO>(
3534 "Reset Button Masked.");
3535 throw std::invalid_argument("Transition Request Masked");
3536 return 0;
3537 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003538 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003539 else
3540 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003541 phosphor::logging::log<phosphor::logging::level::ERR>(
3542 "Unrecognized host state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003543 throw std::invalid_argument("Unrecognized Transition Request");
3544 return 0;
3545 }
3546 resp = requested;
3547 return 1;
3548 });
Lei YU92caa4c2021-02-23 16:59:25 +08003549 hostIface->register_property("CurrentHostState",
3550 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003551
Lei YU92caa4c2021-02-23 16:59:25 +08003552 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003553
3554 // Chassis Control Service
3555 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003556 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003557
3558 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003559 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05303560 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003561 "xyz.openbmc_project.State.Chassis");
3562
Lei YU92caa4c2021-02-23 16:59:25 +08003563 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003564 "RequestedPowerTransition",
3565 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
3566 [](const std::string& requested, std::string& resp) {
3567 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
3568 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003569 // if power button is masked, ignore this
3570 if (!powerButtonMask)
3571 {
3572 sendPowerControlEvent(Event::powerOffRequest);
3573 addRestartCause(RestartCause::command);
3574 }
3575 else
3576 {
3577 phosphor::logging::log<phosphor::logging::level::INFO>(
3578 "Power Button Masked.");
3579 throw std::invalid_argument("Transition Request Masked");
3580 return 0;
3581 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003582 }
3583 else if (requested ==
3584 "xyz.openbmc_project.State.Chassis.Transition.On")
3585 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003586 // if power button is masked, ignore this
3587 if (!powerButtonMask)
3588 {
3589 sendPowerControlEvent(Event::powerOnRequest);
3590 addRestartCause(RestartCause::command);
3591 }
3592 else
3593 {
3594 phosphor::logging::log<phosphor::logging::level::INFO>(
3595 "Power Button Masked.");
3596 throw std::invalid_argument("Transition Request Masked");
3597 return 0;
3598 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003599 }
3600 else if (requested ==
3601 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3602 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003603 // if power button is masked, ignore this
3604 if (!powerButtonMask)
3605 {
3606 sendPowerControlEvent(Event::powerCycleRequest);
3607 addRestartCause(RestartCause::command);
3608 }
3609 else
3610 {
3611 phosphor::logging::log<phosphor::logging::level::INFO>(
3612 "Power Button Masked.");
3613 throw std::invalid_argument("Transition Request Masked");
3614 return 0;
3615 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003616 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003617 else
3618 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003619 phosphor::logging::log<phosphor::logging::level::ERR>(
3620 "Unrecognized chassis state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003621 throw std::invalid_argument("Unrecognized Transition Request");
3622 return 0;
3623 }
3624 resp = requested;
3625 return 1;
3626 });
Lei YU92caa4c2021-02-23 16:59:25 +08003627 chassisIface->register_property("CurrentPowerState",
3628 std::string(getChassisState(powerState)));
3629 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003630
Lei YU92caa4c2021-02-23 16:59:25 +08003631 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003632
Vijay Khemka04175c22020-10-09 14:28:11 -07003633#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003634 // Chassis System Service
3635 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003636 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003637
3638 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003639 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003640 "/xyz/openbmc_project/state/chassis_system0",
3641 "xyz.openbmc_project.State.Chassis");
3642
Lei YU92caa4c2021-02-23 16:59:25 +08003643 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003644 "RequestedPowerTransition",
3645 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3646 [](const std::string& requested, std::string& resp) {
3647 if (requested ==
3648 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3649 {
Lei YU92caa4c2021-02-23 16:59:25 +08003650 systemReset();
3651 addRestartCause(RestartCause::command);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003652 }
3653 else
3654 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003655 phosphor::logging::log<phosphor::logging::level::ERR>(
3656 "Unrecognized chassis system state transition request.");
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003657 throw std::invalid_argument("Unrecognized Transition Request");
3658 return 0;
3659 }
3660 resp = requested;
3661 return 1;
3662 });
Lei YU92caa4c2021-02-23 16:59:25 +08003663 chassisSysIface->register_property(
3664 "CurrentPowerState", std::string(getChassisState(powerState)));
3665 chassisSysIface->register_property("LastStateChangeTime",
3666 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003667
Lei YU92caa4c2021-02-23 16:59:25 +08003668 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003669
Naveen Moses117c34e2021-05-26 20:10:51 +05303670 if (!slotPowerConfig.lineName.empty())
3671 {
3672 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3673 {
3674 return -1;
3675 }
3676
3677 slotPowerState = SlotPowerState::off;
3678 if (slotPowerLine.get_value() > 0)
3679 {
3680 slotPowerState = SlotPowerState::on;
3681 }
3682
3683 chassisSlotIface = chassisSysServer.add_interface(
3684 "/xyz/openbmc_project/state/chassis_system" + node,
3685 "xyz.openbmc_project.State.Chassis");
3686 chassisSlotIface->register_property(
3687 "RequestedPowerTransition",
3688 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3689 [](const std::string& requested, std::string& resp) {
3690 if (requested ==
3691 "xyz.openbmc_project.State.Chassis.Transition.On")
3692 {
3693 slotPowerOn();
3694 }
3695 else if (requested ==
3696 "xyz.openbmc_project.State.Chassis.Transition.Off")
3697 {
3698 slotPowerOff();
3699 }
3700 else if (requested == "xyz.openbmc_project.State.Chassis."
3701 "Transition.PowerCycle")
3702 {
3703 slotPowerCycle();
3704 }
3705 else
3706 {
3707 phosphor::logging::log<phosphor::logging::level::ERR>(
3708 "Unrecognized chassis system state transition "
3709 "request.\n");
3710 throw std::invalid_argument(
3711 "Unrecognized Transition Request");
3712 return 0;
3713 }
3714 resp = requested;
3715 return 1;
3716 });
3717 chassisSlotIface->register_property(
3718 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3719 chassisSlotIface->register_property("LastStateChangeTime",
3720 getCurrentTimeMs());
3721 chassisSlotIface->initialize();
3722 }
3723#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003724 // Buttons Service
3725 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003726 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003727
Priyatharshan P70120512020-09-16 18:47:20 +05303728 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003729 {
Priyatharshan P70120512020-09-16 18:47:20 +05303730 // Power Button Interface
3731 power_control::powerButtonIface = buttonsServer.add_interface(
3732 "/xyz/openbmc_project/chassis/buttons/power",
3733 "xyz.openbmc_project.Chassis.Buttons");
3734
3735 powerButtonIface->register_property(
3736 "ButtonMasked", false, [](const bool requested, bool& current) {
3737 if (requested)
3738 {
3739 if (powerButtonMask)
3740 {
3741 return 1;
3742 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003743 if (!setGPIOOutput(powerOutConfig.lineName,
3744 !powerOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303745 powerButtonMask))
3746 {
3747 throw std::runtime_error("Failed to request GPIO");
3748 return 0;
3749 }
3750 phosphor::logging::log<phosphor::logging::level::INFO>(
3751 "Power Button Masked.");
3752 }
3753 else
3754 {
3755 if (!powerButtonMask)
3756 {
3757 return 1;
3758 }
3759 phosphor::logging::log<phosphor::logging::level::INFO>(
3760 "Power Button Un-masked");
3761 powerButtonMask.reset();
3762 }
3763 // Update the mask setting
3764 current = requested;
3765 return 1;
3766 });
3767
3768 // Check power button state
3769 bool powerButtonPressed;
3770 if (powerButtonConfig.type == ConfigType::GPIO)
3771 {
3772 powerButtonPressed = powerButtonLine.get_value() == 0;
3773 }
3774 else
3775 {
3776 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3777 }
3778
3779 powerButtonIface->register_property("ButtonPressed",
3780 powerButtonPressed);
3781
3782 powerButtonIface->initialize();
3783 }
3784
3785 if (!resetButtonConfig.lineName.empty())
3786 {
3787 // Reset Button Interface
3788
Lei YU92caa4c2021-02-23 16:59:25 +08003789 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003790 "/xyz/openbmc_project/chassis/buttons/reset",
3791 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003792
Lei YU92caa4c2021-02-23 16:59:25 +08003793 resetButtonIface->register_property(
John Wang6c090072020-09-30 13:32:16 +08003794 "ButtonMasked", false, [](const bool requested, bool& current) {
3795 if (requested)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003796 {
Lei YU92caa4c2021-02-23 16:59:25 +08003797 if (resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003798 {
3799 return 1;
3800 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003801 if (!setGPIOOutput(resetOutConfig.lineName,
3802 !resetOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303803 resetButtonMask))
John Wang6c090072020-09-30 13:32:16 +08003804 {
3805 throw std::runtime_error("Failed to request GPIO");
3806 return 0;
3807 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003808 phosphor::logging::log<phosphor::logging::level::INFO>(
3809 "Reset Button Masked.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003810 }
John Wang6c090072020-09-30 13:32:16 +08003811 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003812 {
Lei YU92caa4c2021-02-23 16:59:25 +08003813 if (!resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003814 {
3815 return 1;
3816 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003817 phosphor::logging::log<phosphor::logging::level::INFO>(
3818 "Reset Button Un-masked");
Lei YU92caa4c2021-02-23 16:59:25 +08003819 resetButtonMask.reset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003820 }
John Wang6c090072020-09-30 13:32:16 +08003821 // Update the mask setting
3822 current = requested;
3823 return 1;
3824 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003825
John Wang6c090072020-09-30 13:32:16 +08003826 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303827 bool resetButtonPressed;
3828 if (resetButtonConfig.type == ConfigType::GPIO)
3829 {
3830 resetButtonPressed = resetButtonLine.get_value() == 0;
3831 }
3832 else
3833 {
3834 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3835 }
3836
Lei YU92caa4c2021-02-23 16:59:25 +08003837 resetButtonIface->register_property("ButtonPressed",
3838 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003839
Lei YU92caa4c2021-02-23 16:59:25 +08003840 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003841 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003842
Lei YU92caa4c2021-02-23 16:59:25 +08003843 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003844 {
3845 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003846 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003847 "/xyz/openbmc_project/chassis/buttons/nmi",
3848 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003849
Lei YU92caa4c2021-02-23 16:59:25 +08003850 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003851 "ButtonMasked", false, [](const bool requested, bool& current) {
Lei YU92caa4c2021-02-23 16:59:25 +08003852 if (nmiButtonMasked == requested)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003853 {
3854 // NMI button mask is already set as requested, so no change
3855 return 1;
3856 }
3857 if (requested)
3858 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003859 phosphor::logging::log<phosphor::logging::level::INFO>(
3860 "NMI Button Masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003861 nmiButtonMasked = true;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003862 }
3863 else
3864 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003865 phosphor::logging::log<phosphor::logging::level::INFO>(
3866 "NMI Button Un-masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003867 nmiButtonMasked = false;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003868 }
3869 // Update the mask setting
Lei YU92caa4c2021-02-23 16:59:25 +08003870 current = nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003871 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003872 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003873
Vijay Khemka33a532d2019-11-14 16:50:35 -08003874 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303875 bool nmiButtonPressed;
3876 if (nmiButtonConfig.type == ConfigType::GPIO)
3877 {
3878 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3879 }
3880 else
3881 {
3882 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3883 }
3884
Lei YU92caa4c2021-02-23 16:59:25 +08003885 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003886
Lei YU92caa4c2021-02-23 16:59:25 +08003887 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003888 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003889
Lei YU92caa4c2021-02-23 16:59:25 +08003890 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003891 {
3892 // NMI out Service
3893 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003894 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003895
Vijay Khemka33a532d2019-11-14 16:50:35 -08003896 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303897 nmiOutIface = nmiOutServer.add_interface(
3898 "/xyz/openbmc_project/control/host" + node + "/nmi",
3899 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003900 nmiOutIface->register_method("NMI", nmiReset);
3901 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003902 }
Chen Yugang174ec662019-08-19 19:58:49 +08003903
Lei YU92caa4c2021-02-23 16:59:25 +08003904 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003905 {
3906 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003907 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003908 "/xyz/openbmc_project/chassis/buttons/id",
3909 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003910
Vijay Khemka33a532d2019-11-14 16:50:35 -08003911 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303912 bool idButtonPressed;
3913 if (idButtonConfig.type == ConfigType::GPIO)
3914 {
3915 idButtonPressed = idButtonLine.get_value() == 0;
3916 }
3917 else
3918 {
3919 idButtonPressed = getProperty(idButtonConfig) == 0;
3920 }
3921
Lei YU92caa4c2021-02-23 16:59:25 +08003922 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003923
Lei YU92caa4c2021-02-23 16:59:25 +08003924 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003925 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003926
3927 // OS State Service
3928 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003929 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003930
3931 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003932 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003933 "/xyz/openbmc_project/state/os",
3934 "xyz.openbmc_project.State.OperatingSystem.Status");
3935
3936 // Get the initial OS state based on POST complete
3937 // 0: Asserted, OS state is "Standby" (ready to boot)
3938 // 1: De-Asserted, OS state is "Inactive"
Priyatharshan P70120512020-09-16 18:47:20 +05303939 std::string osState;
3940 if (postCompleteConfig.type == ConfigType::GPIO)
3941 {
3942 osState = postCompleteLine.get_value() > 0 ? "Inactive" : "Standby";
3943 }
3944 else
3945 {
3946 osState = getProperty(postCompleteConfig) > 0 ? "Inactive" : "Standby";
3947 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003948
Lei YU92caa4c2021-02-23 16:59:25 +08003949 osIface->register_property("OperatingSystemState", std::string(osState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003950
Lei YU92caa4c2021-02-23 16:59:25 +08003951 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003952
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003953 // Restart Cause Service
3954 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003955 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003956
3957 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003958 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303959 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003960 "xyz.openbmc_project.Control.Host.RestartCause");
3961
Lei YU92caa4c2021-02-23 16:59:25 +08003962 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003963 "RestartCause",
3964 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3965
Lei YU92caa4c2021-02-23 16:59:25 +08003966 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003967 "RequestedRestartCause",
3968 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3969 [](const std::string& requested, std::string& resp) {
3970 if (requested ==
3971 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3972 {
Lei YU92caa4c2021-02-23 16:59:25 +08003973 addRestartCause(RestartCause::watchdog);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003974 }
3975 else
3976 {
3977 throw std::invalid_argument(
3978 "Unrecognized RestartCause Request");
3979 return 0;
3980 }
3981
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003982 std::string logMsg = "RestartCause requested: " + requested;
3983 phosphor::logging::log<phosphor::logging::level::INFO>(
3984 logMsg.c_str());
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003985 resp = requested;
3986 return 1;
3987 });
3988
Lei YU92caa4c2021-02-23 16:59:25 +08003989 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003990
Lei YU92caa4c2021-02-23 16:59:25 +08003991 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003992
Lei YU92caa4c2021-02-23 16:59:25 +08003993 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003994
3995 return 0;
3996}