blob: 032d6f580986de1540580e2226e03e1706c5d95c [file] [log] [blame]
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001/*
2// Copyright (c) 2018-2019 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#include "i2c.hpp"
17
18#include <sys/sysinfo.h>
19#include <systemd/sd-journal.h>
20
Jason M. Billse63dea02020-08-27 12:07:35 -070021#include <boost/asio/io_service.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070022#include <boost/asio/posix/stream_descriptor.hpp>
Jason M. Billse63dea02020-08-27 12:07:35 -070023#include <boost/asio/steady_timer.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070024#include <boost/container/flat_map.hpp>
Jason M. Bills7d4aaac2019-09-19 14:03:44 -070025#include <boost/container/flat_set.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070026#include <gpiod.hpp>
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053027#include <nlohmann/json.hpp>
Vijay Khemkafc1ecc52020-04-01 10:49:28 -070028#include <phosphor-logging/log.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070029#include <sdbusplus/asio/object_server.hpp>
Vijay Khemka2b6f4422020-05-29 11:13:23 -070030
31#include <filesystem>
32#include <fstream>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070033#include <string_view>
34
35namespace power_control
36{
37static boost::asio::io_service io;
38std::shared_ptr<sdbusplus::asio::connection> conn;
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053039
40static std::string node = "0";
41
Priyatharshan P70120512020-09-16 18:47:20 +053042enum class DbusConfigType
43{
44 name = 1,
45 path,
46 interface,
47 property
48};
49boost::container::flat_map<DbusConfigType, std::string> dbusParams = {
50 {DbusConfigType::name, "DbusName"},
51 {DbusConfigType::path, "Path"},
52 {DbusConfigType::interface, "Interface"},
53 {DbusConfigType::property, "Property"}};
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053054
Priyatharshan P70120512020-09-16 18:47:20 +053055enum class ConfigType
56{
57 GPIO = 1,
58 DBUS
59};
60
61struct ConfigData
62{
63 std::string name;
64 std::string lineName;
65 std::string dbusName;
66 std::string path;
67 std::string interface;
Jean-Marie Verdun50937e72021-08-31 09:15:49 -070068 bool polarity;
Priyatharshan P70120512020-09-16 18:47:20 +053069 ConfigType type;
70};
71
72static ConfigData powerOutConfig;
73static ConfigData powerOkConfig;
74static ConfigData resetOutConfig;
75static ConfigData nmiOutConfig;
76static ConfigData sioPwrGoodConfig;
77static ConfigData sioOnControlConfig;
78static ConfigData sioS5Config;
79static ConfigData postCompleteConfig;
80static ConfigData powerButtonConfig;
81static ConfigData resetButtonConfig;
82static ConfigData idButtonConfig;
83static ConfigData nmiButtonConfig;
Naveen Moses117c34e2021-05-26 20:10:51 +053084static ConfigData slotPowerConfig;
85
Priyatharshan P70120512020-09-16 18:47:20 +053086// map for storing list of gpio parameters whose config are to be read from x86
87// power control json config
88boost::container::flat_map<std::string, ConfigData*> powerSignalMap = {
89 {"PowerOut", &powerOutConfig},
90 {"PowerOk", &powerOkConfig},
91 {"ResetOut", &resetOutConfig},
92 {"NMIOut", &nmiOutConfig},
93 {"SioPowerGood", &sioPwrGoodConfig},
94 {"SioOnControl", &sioOnControlConfig},
95 {"SIOS5", &sioS5Config},
96 {"PostComplete", &postCompleteConfig},
97 {"PowerButton", &powerButtonConfig},
98 {"ResetButton", &resetButtonConfig},
99 {"IdButton", &idButtonConfig},
Naveen Moses117c34e2021-05-26 20:10:51 +0530100 {"NMIButton", &nmiButtonConfig},
101 {"SlotPower", &slotPowerConfig}};
Priyatharshan P70120512020-09-16 18:47:20 +0530102
103static std::string hostDbusName = "xyz.openbmc_project.State.Host";
104static std::string chassisDbusName = "xyz.openbmc_project.State.Chassis";
105static std::string osDbusName = "xyz.openbmc_project.State.OperatingSystem";
106static std::string buttonDbusName = "xyz.openbmc_project.Chassis.Buttons";
107static std::string nmiDbusName = "xyz.openbmc_project.Control.Host.NMI";
108static std::string rstCauseDbusName =
109 "xyz.openbmc_project.Control.Host.RestartCause";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700110static std::shared_ptr<sdbusplus::asio::dbus_interface> hostIface;
111static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700112#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -0700113static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSysIface;
Naveen Moses117c34e2021-05-26 20:10:51 +0530114static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSlotIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700115#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700116static std::shared_ptr<sdbusplus::asio::dbus_interface> powerButtonIface;
117static std::shared_ptr<sdbusplus::asio::dbus_interface> resetButtonIface;
118static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiButtonIface;
119static std::shared_ptr<sdbusplus::asio::dbus_interface> osIface;
120static std::shared_ptr<sdbusplus::asio::dbus_interface> idButtonIface;
Chen Yugang174ec662019-08-19 19:58:49 +0800121static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiOutIface;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700122static std::shared_ptr<sdbusplus::asio::dbus_interface> restartCauseIface;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700123
124static gpiod::line powerButtonMask;
125static gpiod::line resetButtonMask;
126static bool nmiButtonMasked = false;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700127
Priyatharshan P70120512020-09-16 18:47:20 +0530128// This map contains all timer values that are to be read from json config
129boost::container::flat_map<std::string, int> TimerMap = {
130 {"powerPulseTimeMs", 200},
131 {"forceOffPulseTimeMs", 15000},
132 {"resetPulseTimeMs", 500},
133 {"powerCycleTimeMs", 5000},
134 {"sioPowerGoodWatchdogTimeMs", 1000},
135 {"psPowerOKWatchdogTimeMs", 8000},
136 {"gracefulPowerOffTimeS", (5 * 60)},
137 {"warmResetCheckTimeMs", 500},
Naveen Moses117c34e2021-05-26 20:10:51 +0530138 {"powerOffSaveTimeMs", 7000},
139 {"slotPowerCycleTimeMs", 200}};
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700140const static std::filesystem::path powerControlDir = "/var/lib/power-control";
141const static constexpr std::string_view powerStateFile = "power-state";
142
143static bool nmiEnabled = true;
Priyatharshan P19c47a32020-08-12 18:16:43 +0530144static bool sioEnabled = true;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700145
146// Timers
147// Time holding GPIOs asserted
148static boost::asio::steady_timer gpioAssertTimer(io);
149// Time between off and on during a power cycle
150static boost::asio::steady_timer powerCycleTimer(io);
151// Time OS gracefully powering off
152static boost::asio::steady_timer gracefulPowerOffTimer(io);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700153// Time the warm reset check
154static boost::asio::steady_timer warmResetCheckTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700155// Time power supply power OK assertion on power-on
156static boost::asio::steady_timer psPowerOKWatchdogTimer(io);
157// Time SIO power good assertion on power-on
158static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io);
159// Time power-off state save for power loss tracking
160static boost::asio::steady_timer powerStateSaveTimer(io);
161// POH timer
162static boost::asio::steady_timer pohCounterTimer(io);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700163// Time when to allow restart cause updates
164static boost::asio::steady_timer restartCauseTimer(io);
Naveen Moses117c34e2021-05-26 20:10:51 +0530165static boost::asio::steady_timer slotPowerCycleTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700166
167// GPIO Lines and Event Descriptors
168static gpiod::line psPowerOKLine;
169static boost::asio::posix::stream_descriptor psPowerOKEvent(io);
170static gpiod::line sioPowerGoodLine;
171static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io);
172static gpiod::line sioOnControlLine;
173static boost::asio::posix::stream_descriptor sioOnControlEvent(io);
174static gpiod::line sioS5Line;
175static boost::asio::posix::stream_descriptor sioS5Event(io);
176static gpiod::line powerButtonLine;
177static boost::asio::posix::stream_descriptor powerButtonEvent(io);
178static gpiod::line resetButtonLine;
179static boost::asio::posix::stream_descriptor resetButtonEvent(io);
180static gpiod::line nmiButtonLine;
181static boost::asio::posix::stream_descriptor nmiButtonEvent(io);
182static gpiod::line idButtonLine;
183static boost::asio::posix::stream_descriptor idButtonEvent(io);
184static gpiod::line postCompleteLine;
185static boost::asio::posix::stream_descriptor postCompleteEvent(io);
186static gpiod::line nmiOutLine;
Naveen Moses117c34e2021-05-26 20:10:51 +0530187static gpiod::line slotPowerLine;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700188
189static constexpr uint8_t beepPowerFail = 8;
190
191static void beep(const uint8_t& beepPriority)
192{
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800193 std::string logMsg = "Beep with priority: " + std::to_string(beepPriority);
194 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700195
196 conn->async_method_call(
197 [](boost::system::error_code ec) {
198 if (ec)
199 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800200 std::string errMsg =
201 "beep returned error with async_method_call (ec = " +
202 ec.message();
203 phosphor::logging::log<phosphor::logging::level::ERR>(
204 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700205 return;
206 }
207 },
208 "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
209 "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
210}
211
212enum class PowerState
213{
214 on,
215 waitForPSPowerOK,
216 waitForSIOPowerGood,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700217 off,
218 transitionToOff,
219 gracefulTransitionToOff,
220 cycleOff,
221 transitionToCycleOff,
222 gracefulTransitionToCycleOff,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700223 checkForWarmReset,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700224};
225static PowerState powerState;
226static std::string getPowerStateName(PowerState state)
227{
228 switch (state)
229 {
230 case PowerState::on:
231 return "On";
232 break;
233 case PowerState::waitForPSPowerOK:
234 return "Wait for Power Supply Power OK";
235 break;
236 case PowerState::waitForSIOPowerGood:
237 return "Wait for SIO Power Good";
238 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700239 case PowerState::off:
240 return "Off";
241 break;
242 case PowerState::transitionToOff:
243 return "Transition to Off";
244 break;
245 case PowerState::gracefulTransitionToOff:
246 return "Graceful Transition to Off";
247 break;
248 case PowerState::cycleOff:
249 return "Power Cycle Off";
250 break;
251 case PowerState::transitionToCycleOff:
252 return "Transition to Power Cycle Off";
253 break;
254 case PowerState::gracefulTransitionToCycleOff:
255 return "Graceful Transition to Power Cycle Off";
256 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700257 case PowerState::checkForWarmReset:
258 return "Check for Warm Reset";
259 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700260 default:
261 return "unknown state: " + std::to_string(static_cast<int>(state));
262 break;
263 }
264}
265static void logStateTransition(const PowerState state)
266{
Naveen Mosesec972d82021-07-16 21:19:23 +0530267 std::string logMsg = "Host" + node + ": Moving to \"" +
268 getPowerStateName(state) + "\" state";
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700269 phosphor::logging::log<phosphor::logging::level::INFO>(
270 logMsg.c_str(),
Vijay Khemkad6c5ad12020-05-27 14:57:52 -0700271 phosphor::logging::entry("STATE=%s", getPowerStateName(state).c_str()),
Naveen Mosesec972d82021-07-16 21:19:23 +0530272 phosphor::logging::entry("HOST=%s", node.c_str()));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700273}
274
275enum class Event
276{
277 psPowerOKAssert,
278 psPowerOKDeAssert,
279 sioPowerGoodAssert,
280 sioPowerGoodDeAssert,
281 sioS5Assert,
282 sioS5DeAssert,
Jason M. Billsfb957332021-01-28 13:18:46 -0800283 pltRstAssert,
284 pltRstDeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700285 postCompleteAssert,
286 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700287 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700288 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700289 powerCycleTimerExpired,
290 psPowerOKWatchdogTimerExpired,
291 sioPowerGoodWatchdogTimerExpired,
292 gracefulPowerOffTimerExpired,
293 powerOnRequest,
294 powerOffRequest,
295 powerCycleRequest,
296 resetRequest,
297 gracefulPowerOffRequest,
298 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700299 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700300};
301static std::string getEventName(Event event)
302{
303 switch (event)
304 {
305 case Event::psPowerOKAssert:
306 return "power supply power OK assert";
307 break;
308 case Event::psPowerOKDeAssert:
309 return "power supply power OK de-assert";
310 break;
311 case Event::sioPowerGoodAssert:
312 return "SIO power good assert";
313 break;
314 case Event::sioPowerGoodDeAssert:
315 return "SIO power good de-assert";
316 break;
317 case Event::sioS5Assert:
318 return "SIO S5 assert";
319 break;
320 case Event::sioS5DeAssert:
321 return "SIO S5 de-assert";
322 break;
Jason M. Billsfb957332021-01-28 13:18:46 -0800323 case Event::pltRstAssert:
324 return "PLT_RST assert";
325 break;
326 case Event::pltRstDeAssert:
327 return "PLT_RST de-assert";
328 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700329 case Event::postCompleteAssert:
330 return "POST Complete assert";
331 break;
332 case Event::postCompleteDeAssert:
333 return "POST Complete de-assert";
334 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700335 case Event::powerButtonPressed:
336 return "power button pressed";
337 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700338 case Event::resetButtonPressed:
339 return "reset button pressed";
340 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700341 case Event::powerCycleTimerExpired:
342 return "power cycle timer expired";
343 break;
344 case Event::psPowerOKWatchdogTimerExpired:
345 return "power supply power OK watchdog timer expired";
346 break;
347 case Event::sioPowerGoodWatchdogTimerExpired:
348 return "SIO power good watchdog timer expired";
349 break;
350 case Event::gracefulPowerOffTimerExpired:
351 return "graceful power-off timer expired";
352 break;
353 case Event::powerOnRequest:
354 return "power-on request";
355 break;
356 case Event::powerOffRequest:
357 return "power-off request";
358 break;
359 case Event::powerCycleRequest:
360 return "power-cycle request";
361 break;
362 case Event::resetRequest:
363 return "reset request";
364 break;
365 case Event::gracefulPowerOffRequest:
366 return "graceful power-off request";
367 break;
368 case Event::gracefulPowerCycleRequest:
369 return "graceful power-cycle request";
370 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700371 case Event::warmResetDetected:
372 return "warm reset detected";
373 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700374 default:
375 return "unknown event: " + std::to_string(static_cast<int>(event));
376 break;
377 }
378}
379static void logEvent(const std::string_view stateHandler, const Event event)
380{
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700381 std::string logMsg{stateHandler};
382 logMsg += ": " + getEventName(event) + " event received";
383 phosphor::logging::log<phosphor::logging::level::INFO>(
384 logMsg.c_str(),
385 phosphor::logging::entry("EVENT=%s", getEventName(event).c_str()));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700386}
387
388// Power state handlers
389static void powerStateOn(const Event event);
390static void powerStateWaitForPSPowerOK(const Event event);
391static void powerStateWaitForSIOPowerGood(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700392static void powerStateOff(const Event event);
393static void powerStateTransitionToOff(const Event event);
394static void powerStateGracefulTransitionToOff(const Event event);
395static void powerStateCycleOff(const Event event);
396static void powerStateTransitionToCycleOff(const Event event);
397static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700398static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700399
400static std::function<void(const Event)> getPowerStateHandler(PowerState state)
401{
402 switch (state)
403 {
404 case PowerState::on:
405 return powerStateOn;
406 break;
407 case PowerState::waitForPSPowerOK:
408 return powerStateWaitForPSPowerOK;
409 break;
410 case PowerState::waitForSIOPowerGood:
411 return powerStateWaitForSIOPowerGood;
412 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700413 case PowerState::off:
414 return powerStateOff;
415 break;
416 case PowerState::transitionToOff:
417 return powerStateTransitionToOff;
418 break;
419 case PowerState::gracefulTransitionToOff:
420 return powerStateGracefulTransitionToOff;
421 break;
422 case PowerState::cycleOff:
423 return powerStateCycleOff;
424 break;
425 case PowerState::transitionToCycleOff:
426 return powerStateTransitionToCycleOff;
427 break;
428 case PowerState::gracefulTransitionToCycleOff:
429 return powerStateGracefulTransitionToCycleOff;
430 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700431 case PowerState::checkForWarmReset:
432 return powerStateCheckForWarmReset;
433 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700434 default:
Zev Weiss047bcb52020-08-20 21:28:11 +0000435 return nullptr;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700436 break;
437 }
438};
439
440static void sendPowerControlEvent(const Event event)
441{
442 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
443 if (handler == nullptr)
444 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800445 std::string errMsg = "Failed to find handler for power state: " +
446 std::to_string(static_cast<int>(powerState));
447 phosphor::logging::log<phosphor::logging::level::INFO>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700448 return;
449 }
450 handler(event);
451}
452
453static uint64_t getCurrentTimeMs()
454{
455 struct timespec time = {};
456
457 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
458 {
459 return 0;
460 }
461 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
462 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
463
464 return currentTimeMs;
465}
466
467static constexpr std::string_view getHostState(const PowerState state)
468{
469 switch (state)
470 {
471 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700472 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700473 case PowerState::gracefulTransitionToCycleOff:
474 return "xyz.openbmc_project.State.Host.HostState.Running";
475 break;
476 case PowerState::waitForPSPowerOK:
477 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700478 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700479 case PowerState::transitionToOff:
480 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700481 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700482 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700483 return "xyz.openbmc_project.State.Host.HostState.Off";
484 break;
485 default:
486 return "";
487 break;
488 }
489};
490static constexpr std::string_view getChassisState(const PowerState state)
491{
492 switch (state)
493 {
494 case PowerState::on:
495 case PowerState::transitionToOff:
496 case PowerState::gracefulTransitionToOff:
497 case PowerState::transitionToCycleOff:
498 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700499 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700500 return "xyz.openbmc_project.State.Chassis.PowerState.On";
501 break;
502 case PowerState::waitForPSPowerOK:
503 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700504 case PowerState::off:
505 case PowerState::cycleOff:
506 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
507 break;
508 default:
509 return "";
510 break;
511 }
512};
Naveen Moses117c34e2021-05-26 20:10:51 +0530513#ifdef CHASSIS_SYSTEM_RESET
514enum class SlotPowerState
515{
516 on,
517 off,
518};
519static SlotPowerState slotPowerState;
520static constexpr std::string_view getSlotState(const SlotPowerState state)
521{
522 switch (state)
523 {
524 case SlotPowerState::on:
525 return "xyz.openbmc_project.State.Chassis.PowerState.On";
526 break;
527 case SlotPowerState::off:
528 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
529 break;
530 default:
531 return "";
532 break;
533 }
534};
535static void setSlotPowerState(const SlotPowerState state)
536{
537 slotPowerState = state;
538 chassisSlotIface->set_property("CurrentPowerState",
539 std::string(getSlotState(slotPowerState)));
540 chassisSlotIface->set_property("LastStateChangeTime", getCurrentTimeMs());
541}
542#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700543static void savePowerState(const PowerState state)
544{
545 powerStateSaveTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +0530546 std::chrono::milliseconds(TimerMap["powerOffSaveTimeMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700547 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
548 if (ec)
549 {
550 // operation_aborted is expected if timer is canceled before
551 // completion.
552 if (ec != boost::asio::error::operation_aborted)
553 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800554 std::string errMsg =
555 "Power-state save async_wait failed: " + ec.message();
556 phosphor::logging::log<phosphor::logging::level::ERR>(
557 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700558 }
559 return;
560 }
561 std::ofstream powerStateStream(powerControlDir / powerStateFile);
562 powerStateStream << getChassisState(state);
563 });
564}
565static void setPowerState(const PowerState state)
566{
567 powerState = state;
568 logStateTransition(state);
569
570 hostIface->set_property("CurrentHostState",
571 std::string(getHostState(powerState)));
572
573 chassisIface->set_property("CurrentPowerState",
574 std::string(getChassisState(powerState)));
575 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
576
577 // Save the power state for the restore policy
578 savePowerState(state);
579}
580
581enum class RestartCause
582{
583 command,
584 resetButton,
585 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700586 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700587 powerPolicyOn,
588 powerPolicyRestore,
589 softReset,
590};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700591static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700592static std::string getRestartCause(RestartCause cause)
593{
594 switch (cause)
595 {
596 case RestartCause::command:
597 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
598 break;
599 case RestartCause::resetButton:
600 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
601 break;
602 case RestartCause::powerButton:
603 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
604 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700605 case RestartCause::watchdog:
606 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
607 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700608 case RestartCause::powerPolicyOn:
609 return "xyz.openbmc_project.State.Host.RestartCause."
610 "PowerPolicyAlwaysOn";
611 break;
612 case RestartCause::powerPolicyRestore:
613 return "xyz.openbmc_project.State.Host.RestartCause."
614 "PowerPolicyPreviousState";
615 break;
616 case RestartCause::softReset:
617 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
618 break;
619 default:
620 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
621 break;
622 }
623}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700624static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700625{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700626 // Add this to the set of causes for this restart
627 causeSet.insert(cause);
628}
629static void clearRestartCause()
630{
631 // Clear the set for the next restart
632 causeSet.clear();
633}
634static void setRestartCauseProperty(const std::string& cause)
635{
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800636 std::string logMsg = "RestartCause set to " + cause;
637 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700638 restartCauseIface->set_property("RestartCause", cause);
639}
Rashmi RV89f61312020-01-22 15:41:50 +0530640
641static void resetACBootProperty()
642{
643 if ((causeSet.contains(RestartCause::command)) ||
644 (causeSet.contains(RestartCause::softReset)))
645 {
646 conn->async_method_call(
647 [](boost::system::error_code ec) {
648 if (ec)
649 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800650 phosphor::logging::log<phosphor::logging::level::ERR>(
651 "failed to reset ACBoot property");
Rashmi RV89f61312020-01-22 15:41:50 +0530652 }
653 },
654 "xyz.openbmc_project.Settings",
655 "/xyz/openbmc_project/control/host0/ac_boot",
656 "org.freedesktop.DBus.Properties", "Set",
657 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
658 std::variant<std::string>{"False"});
659 }
660}
661
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700662static void setRestartCause()
663{
664 // Determine the actual restart cause based on the set of causes
665 std::string restartCause =
666 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
667 if (causeSet.contains(RestartCause::watchdog))
668 {
669 restartCause = getRestartCause(RestartCause::watchdog);
670 }
671 else if (causeSet.contains(RestartCause::command))
672 {
673 restartCause = getRestartCause(RestartCause::command);
674 }
675 else if (causeSet.contains(RestartCause::resetButton))
676 {
677 restartCause = getRestartCause(RestartCause::resetButton);
678 }
679 else if (causeSet.contains(RestartCause::powerButton))
680 {
681 restartCause = getRestartCause(RestartCause::powerButton);
682 }
683 else if (causeSet.contains(RestartCause::powerPolicyOn))
684 {
685 restartCause = getRestartCause(RestartCause::powerPolicyOn);
686 }
687 else if (causeSet.contains(RestartCause::powerPolicyRestore))
688 {
689 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
690 }
691 else if (causeSet.contains(RestartCause::softReset))
692 {
693 restartCause = getRestartCause(RestartCause::softReset);
694 }
695
696 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700697}
698
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700699static void systemPowerGoodFailedLog()
700{
701 sd_journal_send(
702 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
703 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
704 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Priyatharshan P70120512020-09-16 18:47:20 +0530705 TimerMap["sioPowerGoodWatchdogTimeMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700706}
707
708static void psPowerOKFailedLog()
709{
710 sd_journal_send(
711 "MESSAGE=PowerControl: power supply power good failed to assert",
712 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
713 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Priyatharshan P70120512020-09-16 18:47:20 +0530714 TimerMap["psPowerOKWatchdogTimeMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700715}
716
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700717static void powerRestorePolicyLog()
718{
719 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
720 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
721 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
722}
723
724static void powerButtonPressLog()
725{
726 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
727 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
728 "OpenBMC.0.1.PowerButtonPressed", NULL);
729}
730
731static void resetButtonPressLog()
732{
733 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
734 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
735 "OpenBMC.0.1.ResetButtonPressed", NULL);
736}
737
738static void nmiButtonPressLog()
739{
740 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
741 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
742 "OpenBMC.0.1.NMIButtonPressed", NULL);
743}
744
745static void nmiDiagIntLog()
746{
747 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
748 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
749 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
750}
751
752static int initializePowerStateStorage()
753{
754 // create the power control directory if it doesn't exist
755 std::error_code ec;
756 if (!(std::filesystem::create_directories(powerControlDir, ec)))
757 {
758 if (ec.value() != 0)
759 {
Zev Weiss6b8e3e02021-09-01 22:36:03 -0500760 std::string errMsg = "failed to create " +
761 powerControlDir.string() + ": " + ec.message();
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800762 phosphor::logging::log<phosphor::logging::level::ERR>(
763 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700764 return -1;
765 }
766 }
767 // Create the power state file if it doesn't exist
768 if (!std::filesystem::exists(powerControlDir / powerStateFile))
769 {
770 std::ofstream powerStateStream(powerControlDir / powerStateFile);
771 powerStateStream << getChassisState(powerState);
772 }
773 return 0;
774}
775
776static bool wasPowerDropped()
777{
778 std::ifstream powerStateStream(powerControlDir / powerStateFile);
779 if (!powerStateStream.is_open())
780 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800781 phosphor::logging::log<phosphor::logging::level::ERR>(
782 "Failed to open power state file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700783 return false;
784 }
785
786 std::string state;
787 std::getline(powerStateStream, state);
788 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
789}
790
791static void invokePowerRestorePolicy(const std::string& policy)
792{
793 // Async events may call this twice, but we only want to run once
794 static bool policyInvoked = false;
795 if (policyInvoked)
796 {
797 return;
798 }
799 policyInvoked = true;
800
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800801 std::string logMsg = "Power restore delay expired, invoking " + policy;
802 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700803 if (policy ==
804 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
805 {
806 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700807 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700808 }
809 else if (policy == "xyz.openbmc_project.Control.Power.RestorePolicy."
810 "Policy.Restore")
811 {
812 if (wasPowerDropped())
813 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800814 phosphor::logging::log<phosphor::logging::level::INFO>(
815 "Power was dropped, restoring Host On state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700816 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700817 setRestartCauseProperty(
818 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700819 }
820 else
821 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800822 phosphor::logging::log<phosphor::logging::level::INFO>(
823 "No power drop, restoring Host Off state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700824 }
825 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -0700826 // We're done with the previous power state for the restore policy, so store
827 // the current state
828 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700829}
830
831static void powerRestorePolicyDelay(int delay)
832{
833 // Async events may call this twice, but we only want to run once
834 static bool delayStarted = false;
835 if (delayStarted)
836 {
837 return;
838 }
839 delayStarted = true;
840 // Calculate the delay from now to meet the requested delay
841 // Subtract the approximate uboot time
842 static constexpr const int ubootSeconds = 20;
843 delay -= ubootSeconds;
844 // Subtract the time since boot
845 struct sysinfo info = {};
846 if (sysinfo(&info) == 0)
847 {
848 delay -= info.uptime;
849 }
850 // 0 is the minimum delay
851 delay = std::max(delay, 0);
852
853 static boost::asio::steady_timer powerRestorePolicyTimer(io);
854 powerRestorePolicyTimer.expires_after(std::chrono::seconds(delay));
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800855 std::string logMsg =
856 "Power restore delay of " + std::to_string(delay) + " seconds started";
857 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700858 powerRestorePolicyTimer.async_wait([](const boost::system::error_code ec) {
859 if (ec)
860 {
861 // operation_aborted is expected if timer is canceled before
862 // completion.
863 if (ec != boost::asio::error::operation_aborted)
864 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800865 std::string errMsg =
866 "power restore policy async_wait failed: " + ec.message();
867 phosphor::logging::log<phosphor::logging::level::ERR>(
868 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700869 }
870 return;
871 }
872 // Get Power Restore Policy
873 // In case PowerRestorePolicy is not available, set a match for it
874 static std::unique_ptr<sdbusplus::bus::match::match>
875 powerRestorePolicyMatch = std::make_unique<
876 sdbusplus::bus::match::match>(
877 *conn,
878 "type='signal',interface='org.freedesktop.DBus.Properties',"
879 "member='PropertiesChanged',arg0namespace='xyz.openbmc_"
880 "project.Control.Power.RestorePolicy'",
881 [](sdbusplus::message::message& msg) {
882 std::string interfaceName;
883 boost::container::flat_map<std::string,
884 std::variant<std::string>>
885 propertiesChanged;
886 std::string policy;
887 try
888 {
889 msg.read(interfaceName, propertiesChanged);
890 policy = std::get<std::string>(
891 propertiesChanged.begin()->second);
892 }
893 catch (std::exception& e)
894 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800895 phosphor::logging::log<phosphor::logging::level::ERR>(
896 "Unable to read power restore policy value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700897 powerRestorePolicyMatch.reset();
898 return;
899 }
900 invokePowerRestorePolicy(policy);
901 powerRestorePolicyMatch.reset();
902 });
903
904 // Check if it's already on DBus
905 conn->async_method_call(
906 [](boost::system::error_code ec,
907 const std::variant<std::string>& policyProperty) {
908 if (ec)
909 {
910 return;
911 }
912 powerRestorePolicyMatch.reset();
913 const std::string* policy =
914 std::get_if<std::string>(&policyProperty);
915 if (policy == nullptr)
916 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800917 phosphor::logging::log<phosphor::logging::level::ERR>(
918 "Unable to read power restore policy value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700919 return;
920 }
921 invokePowerRestorePolicy(*policy);
922 },
923 "xyz.openbmc_project.Settings",
924 "/xyz/openbmc_project/control/host0/power_restore_policy",
925 "org.freedesktop.DBus.Properties", "Get",
926 "xyz.openbmc_project.Control.Power.RestorePolicy",
927 "PowerRestorePolicy");
928 });
929}
930
931static void powerRestorePolicyStart()
932{
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800933 phosphor::logging::log<phosphor::logging::level::INFO>(
934 "Power restore policy started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700935 powerRestorePolicyLog();
936
937 // Get the desired delay time
938 // In case PowerRestoreDelay is not available, set a match for it
939 static std::unique_ptr<sdbusplus::bus::match::match>
940 powerRestoreDelayMatch = std::make_unique<sdbusplus::bus::match::match>(
941 *conn,
942 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
943 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Control."
944 "Power.RestoreDelay'",
945 [](sdbusplus::message::message& msg) {
946 std::string interfaceName;
947 boost::container::flat_map<std::string, std::variant<uint16_t>>
948 propertiesChanged;
949 int delay = 0;
950 try
951 {
952 msg.read(interfaceName, propertiesChanged);
953 delay =
954 std::get<uint16_t>(propertiesChanged.begin()->second);
955 }
956 catch (std::exception& e)
957 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800958 phosphor::logging::log<phosphor::logging::level::ERR>(
959 "Unable to read power restore delay value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700960 powerRestoreDelayMatch.reset();
961 return;
962 }
963 powerRestorePolicyDelay(delay);
964 powerRestoreDelayMatch.reset();
965 });
966
967 // Check if it's already on DBus
968 conn->async_method_call(
969 [](boost::system::error_code ec,
970 const std::variant<uint16_t>& delayProperty) {
971 if (ec)
972 {
973 return;
974 }
975 powerRestoreDelayMatch.reset();
976 const uint16_t* delay = std::get_if<uint16_t>(&delayProperty);
977 if (delay == nullptr)
978 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800979 phosphor::logging::log<phosphor::logging::level::ERR>(
980 "Unable to read power restore delay value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700981 return;
982 }
983 powerRestorePolicyDelay(*delay);
984 },
985 "xyz.openbmc_project.Settings",
986 "/xyz/openbmc_project/control/power_restore_delay",
987 "org.freedesktop.DBus.Properties", "Get",
988 "xyz.openbmc_project.Control.Power.RestoreDelay", "PowerRestoreDelay");
989}
990
991static void powerRestorePolicyCheck()
992{
993 // In case ACBoot is not available, set a match for it
994 static std::unique_ptr<sdbusplus::bus::match::match> acBootMatch =
995 std::make_unique<sdbusplus::bus::match::match>(
996 *conn,
997 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
998 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Common."
999 "ACBoot'",
1000 [](sdbusplus::message::message& msg) {
1001 std::string interfaceName;
1002 boost::container::flat_map<std::string,
1003 std::variant<std::string>>
1004 propertiesChanged;
1005 std::string acBoot;
1006 try
1007 {
1008 msg.read(interfaceName, propertiesChanged);
1009 acBoot = std::get<std::string>(
1010 propertiesChanged.begin()->second);
1011 }
1012 catch (std::exception& e)
1013 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001014 phosphor::logging::log<phosphor::logging::level::ERR>(
1015 "Unable to read AC Boot status");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001016 acBootMatch.reset();
1017 return;
1018 }
1019 if (acBoot == "Unknown")
1020 {
1021 return;
1022 }
1023 if (acBoot == "True")
1024 {
1025 // Start the Power Restore policy
1026 powerRestorePolicyStart();
1027 }
1028 acBootMatch.reset();
1029 });
1030
1031 // Check if it's already on DBus
1032 conn->async_method_call(
1033 [](boost::system::error_code ec,
1034 const std::variant<std::string>& acBootProperty) {
1035 if (ec)
1036 {
1037 return;
1038 }
1039 const std::string* acBoot =
1040 std::get_if<std::string>(&acBootProperty);
1041 if (acBoot == nullptr)
1042 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001043 phosphor::logging::log<phosphor::logging::level::ERR>(
1044 "Unable to read AC Boot status");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001045 return;
1046 }
1047 if (*acBoot == "Unknown")
1048 {
1049 return;
1050 }
1051 if (*acBoot == "True")
1052 {
1053 // Start the Power Restore policy
1054 powerRestorePolicyStart();
1055 }
1056 acBootMatch.reset();
1057 },
1058 "xyz.openbmc_project.Settings",
1059 "/xyz/openbmc_project/control/host0/ac_boot",
1060 "org.freedesktop.DBus.Properties", "Get",
1061 "xyz.openbmc_project.Common.ACBoot", "ACBoot");
1062}
1063
1064static bool requestGPIOEvents(
1065 const std::string& name, const std::function<void()>& handler,
1066 gpiod::line& gpioLine,
1067 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
1068{
1069 // Find the GPIO line
1070 gpioLine = gpiod::find_line(name);
1071 if (!gpioLine)
1072 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001073 std::string errMsg = "Failed to find the " + name + " line";
1074 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001075 return false;
1076 }
1077
1078 try
1079 {
1080 gpioLine.request(
1081 {"power-control", gpiod::line_request::EVENT_BOTH_EDGES});
1082 }
1083 catch (std::exception&)
1084 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001085 std::string errMsg = "Failed to request events for " + name;
1086 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001087 return false;
1088 }
1089
1090 int gpioLineFd = gpioLine.event_get_fd();
1091 if (gpioLineFd < 0)
1092 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001093 std::string errMsg = "Failed to name " + name + " fd";
1094 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001095 return false;
1096 }
1097
1098 gpioEventDescriptor.assign(gpioLineFd);
1099
1100 gpioEventDescriptor.async_wait(
1101 boost::asio::posix::stream_descriptor::wait_read,
1102 [&name, handler](const boost::system::error_code ec) {
1103 if (ec)
1104 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001105 std::string errMsg =
1106 name + " fd handler error: " + ec.message();
1107 phosphor::logging::log<phosphor::logging::level::ERR>(
1108 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001109 // TODO: throw here to force power-control to restart?
1110 return;
1111 }
1112 handler();
1113 });
1114 return true;
1115}
1116
1117static bool setGPIOOutput(const std::string& name, const int value,
1118 gpiod::line& gpioLine)
1119{
1120 // Find the GPIO line
1121 gpioLine = gpiod::find_line(name);
1122 if (!gpioLine)
1123 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001124 std::string errMsg = "Failed to find the " + name + " line";
1125 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001126 return false;
1127 }
1128
1129 // Request GPIO output to specified value
1130 try
1131 {
1132 gpioLine.request({__FUNCTION__, gpiod::line_request::DIRECTION_OUTPUT},
1133 value);
1134 }
1135 catch (std::exception&)
1136 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001137 std::string errMsg = "Failed to request " + name + " output";
1138 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001139 return false;
1140 }
1141
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001142 std::string logMsg = name + " set to " + std::to_string(value);
1143 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001144 return true;
1145}
1146
1147static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1148 const std::string& name, const int value,
1149 const int durationMs)
1150{
1151 // Set the masked GPIO line to the specified value
1152 maskedGPIOLine.set_value(value);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001153 std::string logMsg = name + " set to " + std::to_string(value);
1154 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001155 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001156 gpioAssertTimer.async_wait([maskedGPIOLine, value,
1157 name](const boost::system::error_code ec) {
1158 // Set the masked GPIO line back to the opposite value
1159 maskedGPIOLine.set_value(!value);
1160 std::string logMsg = name + " released";
1161 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
1162 if (ec)
1163 {
1164 // operation_aborted is expected if timer is canceled before
1165 // completion.
1166 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001167 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001168 std::string errMsg =
1169 name + " async_wait failed: " + ec.message();
1170 phosphor::logging::log<phosphor::logging::level::ERR>(
1171 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001172 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001173 }
1174 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001175 return 0;
1176}
1177
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001178static int setGPIOOutputForMs(const ConfigData& config, const int value,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001179 const int durationMs)
1180{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001181 int polarizedvalue;
1182 if (!config.polarity)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001183 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001184 polarizedvalue = value;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001185 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001186 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001187 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001188 polarizedvalue = !value;
1189 }
1190 // If the requested GPIO is masked, use the mask line to set the output
1191 if (powerButtonMask && config.lineName == powerOutConfig.lineName)
1192 {
1193 return setMaskedGPIOOutputForMs(powerButtonMask, config.lineName,
1194 polarizedvalue, durationMs);
1195 }
1196 if (resetButtonMask && config.lineName == resetOutConfig.lineName)
1197 {
1198 return setMaskedGPIOOutputForMs(resetButtonMask, config.lineName,
1199 polarizedvalue, durationMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001200 }
1201
1202 // No mask set, so request and set the GPIO normally
1203 gpiod::line gpioLine;
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001204 if (!setGPIOOutput(config.lineName, polarizedvalue, gpioLine))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001205 {
1206 return -1;
1207 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001208 const std::string name = config.lineName;
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001209
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001210 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001211 gpioAssertTimer.async_wait([gpioLine, polarizedvalue,
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001212 name](const boost::system::error_code ec) {
1213 // Set the GPIO line back to the opposite value
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001214 gpioLine.set_value(!polarizedvalue);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001215 std::string logMsg = name + " released";
1216 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
1217 if (ec)
1218 {
1219 // operation_aborted is expected if timer is canceled before
1220 // completion.
1221 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001222 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001223 std::string errMsg =
1224 name + " async_wait failed: " + ec.message();
1225 phosphor::logging::log<phosphor::logging::level::ERR>(
1226 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001227 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001228 }
1229 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001230 return 0;
1231}
1232
1233static void powerOn()
1234{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001235 setGPIOOutputForMs(powerOutConfig, 0, TimerMap["powerPulseTimeMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001236}
Naveen Moses117c34e2021-05-26 20:10:51 +05301237#ifdef CHASSIS_SYSTEM_RESET
1238static int slotPowerOn()
1239{
1240 if (power_control::slotPowerState != power_control::SlotPowerState::on)
1241 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001242
Naveen Moses117c34e2021-05-26 20:10:51 +05301243 slotPowerLine.set_value(1);
1244
1245 if (slotPowerLine.get_value() > 0)
1246 {
1247 setSlotPowerState(SlotPowerState::on);
1248 phosphor::logging::log<phosphor::logging::level::INFO>(
1249 "Slot Power is switched On\n");
1250 }
1251 else
1252 {
1253 return -1;
1254 }
1255 }
1256 else
1257 {
1258 phosphor::logging::log<phosphor::logging::level::INFO>(
1259 "Slot Power is already in 'On' state\n");
1260 return -1;
1261 }
1262 return 0;
1263}
1264static int slotPowerOff()
1265{
1266 if (power_control::slotPowerState != power_control::SlotPowerState::off)
1267 {
1268 slotPowerLine.set_value(0);
1269
1270 if (!(slotPowerLine.get_value() > 0))
1271 {
1272 setSlotPowerState(SlotPowerState::off);
1273 setPowerState(PowerState::off);
1274 phosphor::logging::log<phosphor::logging::level::INFO>(
1275 "Slot Power is switched Off\n");
1276 }
1277 else
1278 {
1279 return -1;
1280 }
1281 }
1282 else
1283 {
1284 phosphor::logging::log<phosphor::logging::level::INFO>(
1285 "Slot Power is already in 'Off' state\n");
1286 return -1;
1287 }
1288 return 0;
1289}
1290static void slotPowerCycle()
1291{
1292 phosphor::logging::log<phosphor::logging::level::INFO>(
1293 "Slot Power Cycle started\n");
1294 slotPowerOff();
1295 slotPowerCycleTimer.expires_after(
1296 std::chrono::milliseconds(TimerMap["slotPowerCycleTimeMs"]));
1297 slotPowerCycleTimer.async_wait([](const boost::system::error_code ec) {
1298 if (ec)
1299 {
1300 if (ec != boost::asio::error::operation_aborted)
1301 {
1302 std::string errMsg =
1303 "Slot Power cycle timer async_wait failed: " + ec.message();
1304 phosphor::logging::log<phosphor::logging::level::ERR>(
1305 errMsg.c_str());
1306 }
1307 phosphor::logging::log<phosphor::logging::level::INFO>(
1308 "Slot Power cycle timer canceled\n");
1309 return;
1310 }
1311 phosphor::logging::log<phosphor::logging::level::INFO>(
1312 "Slot Power cycle timer completed\n");
1313 slotPowerOn();
1314 phosphor::logging::log<phosphor::logging::level::INFO>(
1315 "Slot Power Cycle Completed\n");
1316 });
1317}
1318#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001319static void gracefulPowerOff()
1320{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001321 setGPIOOutputForMs(powerOutConfig, 0, TimerMap["powerPulseTimeMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001322}
1323
1324static void forcePowerOff()
1325{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001326 if (setGPIOOutputForMs(powerOutConfig, 0, TimerMap["forceOffPulseTimeMs"]) <
1327 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001328 {
1329 return;
1330 }
1331
1332 // If the force off timer expires, then the PCH power-button override
1333 // failed, so attempt the Unconditional Powerdown SMBus command.
1334 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1335 if (ec)
1336 {
1337 // operation_aborted is expected if timer is canceled before
1338 // completion.
1339 if (ec != boost::asio::error::operation_aborted)
1340 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001341 std::string errMsg =
1342 "Force power off async_wait failed: " + ec.message();
1343 phosphor::logging::log<phosphor::logging::level::ERR>(
1344 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001345 }
1346 return;
1347 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001348
1349 phosphor::logging::log<phosphor::logging::level::INFO>(
1350 "PCH Power-button override failed. Issuing Unconditional Powerdown "
1351 "SMBus command.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001352 const static constexpr size_t pchDevBusAddress = 3;
1353 const static constexpr size_t pchDevSlaveAddress = 0x44;
1354 const static constexpr size_t pchCmdReg = 0;
1355 const static constexpr size_t pchPowerDownCmd = 0x02;
1356 if (i2cSet(pchDevBusAddress, pchDevSlaveAddress, pchCmdReg,
1357 pchPowerDownCmd) < 0)
1358 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001359 phosphor::logging::log<phosphor::logging::level::ERR>(
1360 "Unconditional Powerdown command failed! Not sure what to do "
1361 "now.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001362 }
1363 });
1364}
1365
1366static void reset()
1367{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001368 setGPIOOutputForMs(resetOutConfig, 0, TimerMap["resetPulseTimeMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001369}
1370
1371static void gracefulPowerOffTimerStart()
1372{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001373 phosphor::logging::log<phosphor::logging::level::INFO>(
1374 "Graceful power-off timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001375 gracefulPowerOffTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301376 std::chrono::seconds(TimerMap["gracefulPowerOffTimeS"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001377 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1378 if (ec)
1379 {
1380 // operation_aborted is expected if timer is canceled before
1381 // completion.
1382 if (ec != boost::asio::error::operation_aborted)
1383 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001384 std::string errMsg =
1385 "Graceful power-off async_wait failed: " + ec.message();
1386 phosphor::logging::log<phosphor::logging::level::ERR>(
1387 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001388 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001389 phosphor::logging::log<phosphor::logging::level::INFO>(
1390 "Graceful power-off timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001391 return;
1392 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001393 phosphor::logging::log<phosphor::logging::level::INFO>(
1394 "Graceful power-off timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001395 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1396 });
1397}
1398
1399static void powerCycleTimerStart()
1400{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001401 phosphor::logging::log<phosphor::logging::level::INFO>(
1402 "Power-cycle timer started");
Priyatharshan P70120512020-09-16 18:47:20 +05301403 powerCycleTimer.expires_after(
1404 std::chrono::milliseconds(TimerMap["powerCycleTimeMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001405 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1406 if (ec)
1407 {
1408 // operation_aborted is expected if timer is canceled before
1409 // completion.
1410 if (ec != boost::asio::error::operation_aborted)
1411 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001412 std::string errMsg =
1413 "Power-cycle async_wait failed: " + ec.message();
1414 phosphor::logging::log<phosphor::logging::level::ERR>(
1415 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001416 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001417 phosphor::logging::log<phosphor::logging::level::INFO>(
1418 "Power-cycle timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001419 return;
1420 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001421 phosphor::logging::log<phosphor::logging::level::INFO>(
1422 "Power-cycle timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001423 sendPowerControlEvent(Event::powerCycleTimerExpired);
1424 });
1425}
1426
1427static void psPowerOKWatchdogTimerStart()
1428{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001429 phosphor::logging::log<phosphor::logging::level::INFO>(
1430 "power supply power OK watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001431 psPowerOKWatchdogTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301432 std::chrono::milliseconds(TimerMap["psPowerOKWatchdogTimeMs"]));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001433 psPowerOKWatchdogTimer.async_wait([](const boost::system::error_code ec) {
1434 if (ec)
1435 {
1436 // operation_aborted is expected if timer is canceled before
1437 // completion.
1438 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001439 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001440 std::string errMsg =
1441 "power supply power OK watchdog async_wait failed: " +
1442 ec.message();
1443 phosphor::logging::log<phosphor::logging::level::ERR>(
1444 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001445 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001446 phosphor::logging::log<phosphor::logging::level::INFO>(
1447 "power supply power OK watchdog timer canceled");
1448 return;
1449 }
1450 phosphor::logging::log<phosphor::logging::level::INFO>(
1451 "power supply power OK watchdog timer expired");
1452 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1453 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001454}
1455
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001456static void warmResetCheckTimerStart()
1457{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001458 phosphor::logging::log<phosphor::logging::level::INFO>(
1459 "Warm reset check timer started");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001460 warmResetCheckTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301461 std::chrono::milliseconds(TimerMap["warmResetCheckTimeMs"]));
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001462 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1463 if (ec)
1464 {
1465 // operation_aborted is expected if timer is canceled before
1466 // completion.
1467 if (ec != boost::asio::error::operation_aborted)
1468 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001469 std::string errMsg =
1470 "Warm reset check async_wait failed: " + ec.message();
1471 phosphor::logging::log<phosphor::logging::level::ERR>(
1472 errMsg.c_str());
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001473 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001474 phosphor::logging::log<phosphor::logging::level::INFO>(
1475 "Warm reset check timer canceled");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001476 return;
1477 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001478 phosphor::logging::log<phosphor::logging::level::INFO>(
1479 "Warm reset check timer completed");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001480 sendPowerControlEvent(Event::warmResetDetected);
1481 });
1482}
1483
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001484static void pohCounterTimerStart()
1485{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001486 phosphor::logging::log<phosphor::logging::level::INFO>("POH timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001487 // Set the time-out as 1 hour, to align with POH command in ipmid
1488 pohCounterTimer.expires_after(std::chrono::hours(1));
1489 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1490 if (ec)
1491 {
1492 // operation_aborted is expected if timer is canceled before
1493 // completion.
1494 if (ec != boost::asio::error::operation_aborted)
1495 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001496 std::string errMsg =
1497 "POH timer async_wait failed: " + ec.message();
1498 phosphor::logging::log<phosphor::logging::level::ERR>(
1499 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001500 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001501 phosphor::logging::log<phosphor::logging::level::INFO>(
1502 "POH timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001503 return;
1504 }
1505
1506 if (getHostState(powerState) !=
1507 "xyz.openbmc_project.State.Host.HostState.Running")
1508 {
1509 return;
1510 }
1511
1512 conn->async_method_call(
1513 [](boost::system::error_code ec,
1514 const std::variant<uint32_t>& pohCounterProperty) {
1515 if (ec)
1516 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001517 phosphor::logging::log<phosphor::logging::level::INFO>(
1518 "error to get poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001519 return;
1520 }
1521 const uint32_t* pohCounter =
1522 std::get_if<uint32_t>(&pohCounterProperty);
1523 if (pohCounter == nullptr)
1524 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001525 phosphor::logging::log<phosphor::logging::level::INFO>(
1526 "unable to read poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001527 return;
1528 }
1529
1530 conn->async_method_call(
1531 [](boost::system::error_code ec) {
1532 if (ec)
1533 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001534 phosphor::logging::log<
1535 phosphor::logging::level::INFO>(
1536 "failed to set poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001537 }
1538 },
1539 "xyz.openbmc_project.Settings",
1540 "/xyz/openbmc_project/state/chassis0",
1541 "org.freedesktop.DBus.Properties", "Set",
1542 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1543 std::variant<uint32_t>(*pohCounter + 1));
1544 },
1545 "xyz.openbmc_project.Settings",
1546 "/xyz/openbmc_project/state/chassis0",
1547 "org.freedesktop.DBus.Properties", "Get",
1548 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1549
1550 pohCounterTimerStart();
1551 });
1552}
1553
1554static void currentHostStateMonitor()
1555{
Yong Li8d660212019-12-27 10:18:10 +08001556 if (getHostState(powerState) ==
1557 "xyz.openbmc_project.State.Host.HostState.Running")
1558 {
1559 pohCounterTimerStart();
1560 // Clear the restart cause set for the next restart
1561 clearRestartCause();
1562 }
1563 else
1564 {
1565 pohCounterTimer.cancel();
1566 // Set the restart cause set for this restart
1567 setRestartCause();
1568 }
1569
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001570 static auto match = sdbusplus::bus::match::match(
1571 *conn,
1572 "type='signal',member='PropertiesChanged', "
1573 "interface='org.freedesktop.DBus.Properties', "
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001574 "arg0='xyz.openbmc_project.State.Host'",
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001575 [](sdbusplus::message::message& message) {
1576 std::string intfName;
1577 std::map<std::string, std::variant<std::string>> properties;
1578
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001579 try
1580 {
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001581 message.read(intfName, properties);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001582 }
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001583 catch (std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001584 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001585 phosphor::logging::log<phosphor::logging::level::ERR>(
1586 "Unable to read host state");
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001587 return;
1588 }
1589 if (properties.empty())
1590 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001591 phosphor::logging::log<phosphor::logging::level::ERR>(
1592 "ERROR: Empty PropertiesChanged signal received");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001593 return;
1594 }
1595
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001596 // We only want to check for CurrentHostState
1597 if (properties.begin()->first != "CurrentHostState")
1598 {
1599 return;
1600 }
1601 std::string* currentHostState =
1602 std::get_if<std::string>(&(properties.begin()->second));
1603 if (currentHostState == nullptr)
1604 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001605 std::string errMsg =
1606 properties.begin()->first + " property invalid";
1607 phosphor::logging::log<phosphor::logging::level::ERR>(
1608 errMsg.c_str());
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001609 return;
1610 }
1611
1612 if (*currentHostState ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001613 "xyz.openbmc_project.State.Host.HostState.Running")
1614 {
1615 pohCounterTimerStart();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001616 // Clear the restart cause set for the next restart
1617 clearRestartCause();
Yong Li8d660212019-12-27 10:18:10 +08001618 sd_journal_send("MESSAGE=Host system DC power is on",
1619 "PRIORITY=%i", LOG_INFO,
1620 "REDFISH_MESSAGE_ID=%s",
1621 "OpenBMC.0.1.DCPowerOn", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001622 }
1623 else
1624 {
1625 pohCounterTimer.cancel();
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301626 // POST_COMPLETE GPIO event is not working in some platforms
1627 // when power state is changed to OFF. This resulted in
1628 // 'OperatingSystemState' to stay at 'Standby', even though
1629 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1630 // if HostState is trurned to OFF.
1631 osIface->set_property("OperatingSystemState",
1632 std::string("Inactive"));
1633
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001634 // Set the restart cause set for this restart
1635 setRestartCause();
Rashmi RV89f61312020-01-22 15:41:50 +05301636 resetACBootProperty();
Yong Li8d660212019-12-27 10:18:10 +08001637 sd_journal_send("MESSAGE=Host system DC power is off",
1638 "PRIORITY=%i", LOG_INFO,
1639 "REDFISH_MESSAGE_ID=%s",
1640 "OpenBMC.0.1.DCPowerOff", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001641 }
1642 });
1643}
1644
1645static void sioPowerGoodWatchdogTimerStart()
1646{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001647 phosphor::logging::log<phosphor::logging::level::INFO>(
1648 "SIO power good watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001649 sioPowerGoodWatchdogTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301650 std::chrono::milliseconds(TimerMap["sioPowerGoodWatchdogTimeMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001651 sioPowerGoodWatchdogTimer.async_wait(
1652 [](const boost::system::error_code ec) {
1653 if (ec)
1654 {
1655 // operation_aborted is expected if timer is canceled before
1656 // completion.
1657 if (ec != boost::asio::error::operation_aborted)
1658 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001659 std::string errMsg =
1660 "SIO power good watchdog async_wait failed: " +
1661 ec.message();
1662 phosphor::logging::log<phosphor::logging::level::ERR>(
1663 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001664 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001665 phosphor::logging::log<phosphor::logging::level::INFO>(
1666 "SIO power good watchdog timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001667 return;
1668 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001669 phosphor::logging::log<phosphor::logging::level::INFO>(
1670 "SIO power good watchdog timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001671 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1672 });
1673}
1674
1675static void powerStateOn(const Event event)
1676{
1677 logEvent(__FUNCTION__, event);
1678 switch (event)
1679 {
1680 case Event::psPowerOKDeAssert:
1681 setPowerState(PowerState::off);
1682 // DC power is unexpectedly lost, beep
1683 beep(beepPowerFail);
1684 break;
1685 case Event::sioS5Assert:
1686 setPowerState(PowerState::transitionToOff);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001687 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001688 break;
Jason M. Billsfb957332021-01-28 13:18:46 -08001689#if USE_PLT_RST
1690 case Event::pltRstAssert:
1691#else
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001692 case Event::postCompleteDeAssert:
Jason M. Billsfb957332021-01-28 13:18:46 -08001693#endif
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001694 setPowerState(PowerState::checkForWarmReset);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001695 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001696 warmResetCheckTimerStart();
1697 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001698 case Event::powerButtonPressed:
1699 setPowerState(PowerState::gracefulTransitionToOff);
1700 gracefulPowerOffTimerStart();
1701 break;
1702 case Event::powerOffRequest:
1703 setPowerState(PowerState::transitionToOff);
1704 forcePowerOff();
1705 break;
1706 case Event::gracefulPowerOffRequest:
1707 setPowerState(PowerState::gracefulTransitionToOff);
1708 gracefulPowerOffTimerStart();
1709 gracefulPowerOff();
1710 break;
1711 case Event::powerCycleRequest:
1712 setPowerState(PowerState::transitionToCycleOff);
1713 forcePowerOff();
1714 break;
1715 case Event::gracefulPowerCycleRequest:
1716 setPowerState(PowerState::gracefulTransitionToCycleOff);
1717 gracefulPowerOffTimerStart();
1718 gracefulPowerOff();
1719 break;
1720 case Event::resetRequest:
1721 reset();
1722 break;
1723 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001724 phosphor::logging::log<phosphor::logging::level::INFO>(
1725 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001726 break;
1727 }
1728}
1729
1730static void powerStateWaitForPSPowerOK(const Event event)
1731{
1732 logEvent(__FUNCTION__, event);
1733 switch (event)
1734 {
1735 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301736 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001737 // Cancel any GPIO assertions held during the transition
1738 gpioAssertTimer.cancel();
1739 psPowerOKWatchdogTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301740 if (sioEnabled == true)
1741 {
1742 sioPowerGoodWatchdogTimerStart();
1743 setPowerState(PowerState::waitForSIOPowerGood);
1744 }
1745 else
1746 {
1747 setPowerState(PowerState::on);
1748 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001749 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301750 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001751 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001752 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001753 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001754 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001755 case Event::sioPowerGoodAssert:
1756 psPowerOKWatchdogTimer.cancel();
1757 setPowerState(PowerState::on);
1758 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001759 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001760 phosphor::logging::log<phosphor::logging::level::INFO>(
1761 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001762 break;
1763 }
1764}
1765
1766static void powerStateWaitForSIOPowerGood(const Event event)
1767{
1768 logEvent(__FUNCTION__, event);
1769 switch (event)
1770 {
1771 case Event::sioPowerGoodAssert:
1772 sioPowerGoodWatchdogTimer.cancel();
1773 setPowerState(PowerState::on);
1774 break;
1775 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001776 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001777 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001778 break;
1779 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001780 phosphor::logging::log<phosphor::logging::level::INFO>(
1781 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001782 break;
1783 }
1784}
1785
1786static void powerStateOff(const Event event)
1787{
1788 logEvent(__FUNCTION__, event);
1789 switch (event)
1790 {
1791 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301792 {
1793 if (sioEnabled == true)
1794 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001795 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301796 setPowerState(PowerState::waitForSIOPowerGood);
1797 }
1798 else
1799 {
1800 setPowerState(PowerState::on);
1801 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001802 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301803 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001804 case Event::sioS5DeAssert:
1805 setPowerState(PowerState::waitForPSPowerOK);
1806 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001807 case Event::sioPowerGoodAssert:
1808 setPowerState(PowerState::on);
1809 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001810 case Event::powerButtonPressed:
1811 psPowerOKWatchdogTimerStart();
1812 setPowerState(PowerState::waitForPSPowerOK);
1813 break;
1814 case Event::powerOnRequest:
1815 psPowerOKWatchdogTimerStart();
1816 setPowerState(PowerState::waitForPSPowerOK);
1817 powerOn();
1818 break;
1819 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001820 phosphor::logging::log<phosphor::logging::level::INFO>(
1821 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001822 break;
1823 }
1824}
1825
1826static void powerStateTransitionToOff(const Event event)
1827{
1828 logEvent(__FUNCTION__, event);
1829 switch (event)
1830 {
1831 case Event::psPowerOKDeAssert:
1832 // Cancel any GPIO assertions held during the transition
1833 gpioAssertTimer.cancel();
1834 setPowerState(PowerState::off);
1835 break;
1836 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001837 phosphor::logging::log<phosphor::logging::level::INFO>(
1838 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001839 break;
1840 }
1841}
1842
1843static void powerStateGracefulTransitionToOff(const Event event)
1844{
1845 logEvent(__FUNCTION__, event);
1846 switch (event)
1847 {
1848 case Event::psPowerOKDeAssert:
1849 gracefulPowerOffTimer.cancel();
1850 setPowerState(PowerState::off);
1851 break;
1852 case Event::gracefulPowerOffTimerExpired:
1853 setPowerState(PowerState::on);
1854 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001855 case Event::powerOffRequest:
1856 gracefulPowerOffTimer.cancel();
1857 setPowerState(PowerState::transitionToOff);
1858 forcePowerOff();
1859 break;
1860 case Event::powerCycleRequest:
1861 gracefulPowerOffTimer.cancel();
1862 setPowerState(PowerState::transitionToCycleOff);
1863 forcePowerOff();
1864 break;
1865 case Event::resetRequest:
1866 gracefulPowerOffTimer.cancel();
1867 setPowerState(PowerState::on);
1868 reset();
1869 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001870 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001871 phosphor::logging::log<phosphor::logging::level::INFO>(
1872 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001873 break;
1874 }
1875}
1876
1877static void powerStateCycleOff(const Event event)
1878{
1879 logEvent(__FUNCTION__, event);
1880 switch (event)
1881 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001882 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301883 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001884 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301885 if (sioEnabled == true)
1886 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001887 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301888 setPowerState(PowerState::waitForSIOPowerGood);
1889 }
1890 else
1891 {
1892 setPowerState(PowerState::on);
1893 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001894 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301895 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001896 case Event::sioS5DeAssert:
1897 powerCycleTimer.cancel();
1898 setPowerState(PowerState::waitForPSPowerOK);
1899 break;
1900 case Event::powerButtonPressed:
1901 powerCycleTimer.cancel();
1902 psPowerOKWatchdogTimerStart();
1903 setPowerState(PowerState::waitForPSPowerOK);
1904 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001905 case Event::powerCycleTimerExpired:
1906 psPowerOKWatchdogTimerStart();
1907 setPowerState(PowerState::waitForPSPowerOK);
1908 powerOn();
1909 break;
1910 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001911 phosphor::logging::log<phosphor::logging::level::INFO>(
1912 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001913 break;
1914 }
1915}
1916
1917static void powerStateTransitionToCycleOff(const Event event)
1918{
1919 logEvent(__FUNCTION__, event);
1920 switch (event)
1921 {
1922 case Event::psPowerOKDeAssert:
1923 // Cancel any GPIO assertions held during the transition
1924 gpioAssertTimer.cancel();
1925 setPowerState(PowerState::cycleOff);
1926 powerCycleTimerStart();
1927 break;
1928 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001929 phosphor::logging::log<phosphor::logging::level::INFO>(
1930 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001931 break;
1932 }
1933}
1934
1935static void powerStateGracefulTransitionToCycleOff(const Event event)
1936{
1937 logEvent(__FUNCTION__, event);
1938 switch (event)
1939 {
1940 case Event::psPowerOKDeAssert:
1941 gracefulPowerOffTimer.cancel();
1942 setPowerState(PowerState::cycleOff);
1943 powerCycleTimerStart();
1944 break;
1945 case Event::gracefulPowerOffTimerExpired:
1946 setPowerState(PowerState::on);
1947 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001948 case Event::powerOffRequest:
1949 gracefulPowerOffTimer.cancel();
1950 setPowerState(PowerState::transitionToOff);
1951 forcePowerOff();
1952 break;
1953 case Event::powerCycleRequest:
1954 gracefulPowerOffTimer.cancel();
1955 setPowerState(PowerState::transitionToCycleOff);
1956 forcePowerOff();
1957 break;
1958 case Event::resetRequest:
1959 gracefulPowerOffTimer.cancel();
1960 setPowerState(PowerState::on);
1961 reset();
1962 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001963 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001964 phosphor::logging::log<phosphor::logging::level::INFO>(
1965 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001966 break;
1967 }
1968}
1969
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001970static void powerStateCheckForWarmReset(const Event event)
1971{
1972 logEvent(__FUNCTION__, event);
1973 switch (event)
1974 {
1975 case Event::sioS5Assert:
1976 warmResetCheckTimer.cancel();
1977 setPowerState(PowerState::transitionToOff);
1978 break;
1979 case Event::warmResetDetected:
1980 setPowerState(PowerState::on);
1981 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001982 case Event::psPowerOKDeAssert:
1983 warmResetCheckTimer.cancel();
1984 setPowerState(PowerState::off);
1985 // DC power is unexpectedly lost, beep
1986 beep(beepPowerFail);
1987 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001988 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001989 phosphor::logging::log<phosphor::logging::level::INFO>(
1990 "No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001991 break;
1992 }
1993}
1994
Zev Weiss584aa132021-09-02 19:21:52 -05001995static void psPowerOKHandler(bool state)
1996{
1997 Event powerControlEvent =
1998 state ? Event::psPowerOKAssert : Event::psPowerOKDeAssert;
1999 sendPowerControlEvent(powerControlEvent);
2000}
2001
2002static void psPowerOKGPIOHandler()
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002003{
2004 gpiod::line_event gpioLineEvent = psPowerOKLine.event_read();
2005
Zev Weiss584aa132021-09-02 19:21:52 -05002006 psPowerOKHandler(gpioLineEvent.event_type ==
2007 gpiod::line_event::RISING_EDGE);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002008
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002009 psPowerOKEvent.async_wait(
2010 boost::asio::posix::stream_descriptor::wait_read,
2011 [](const boost::system::error_code ec) {
2012 if (ec)
2013 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002014 std::string errMsg =
2015 "power supply power OK handler error: " + ec.message();
2016 phosphor::logging::log<phosphor::logging::level::ERR>(
2017 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002018 return;
2019 }
Zev Weiss584aa132021-09-02 19:21:52 -05002020 psPowerOKGPIOHandler();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002021 });
2022}
2023
Zev Weiss584aa132021-09-02 19:21:52 -05002024static void sioPowerGoodHandler(bool state)
2025{
2026 Event powerControlEvent =
2027 state ? Event::sioPowerGoodAssert : Event::sioPowerGoodDeAssert;
2028 sendPowerControlEvent(powerControlEvent);
2029}
2030
2031static void sioPowerGoodGPIOHandler()
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002032{
2033 gpiod::line_event gpioLineEvent = sioPowerGoodLine.event_read();
2034
Zev Weiss584aa132021-09-02 19:21:52 -05002035 sioPowerGoodHandler(gpioLineEvent.event_type ==
2036 gpiod::line_event::RISING_EDGE);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002037
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002038 sioPowerGoodEvent.async_wait(
2039 boost::asio::posix::stream_descriptor::wait_read,
2040 [](const boost::system::error_code ec) {
2041 if (ec)
2042 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002043 std::string errMsg =
2044 "SIO power good handler error: " + ec.message();
2045 phosphor::logging::log<phosphor::logging::level::ERR>(
2046 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002047 return;
2048 }
Zev Weiss584aa132021-09-02 19:21:52 -05002049 sioPowerGoodGPIOHandler();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002050 });
2051}
2052
Zev Weiss584aa132021-09-02 19:21:52 -05002053static void sioOnControlHandler(bool state)
2054{
2055 std::string logMsg =
2056 "SIO_ONCONTROL value changed: " + std::to_string(state);
2057 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
2058}
2059
2060static void sioOnControlGPIOHandler()
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002061{
2062 gpiod::line_event gpioLineEvent = sioOnControlLine.event_read();
2063
Zev Weiss584aa132021-09-02 19:21:52 -05002064 sioOnControlHandler(gpioLineEvent.event_type ==
2065 gpiod::line_event::RISING_EDGE);
2066
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002067 sioOnControlEvent.async_wait(
2068 boost::asio::posix::stream_descriptor::wait_read,
2069 [](const boost::system::error_code ec) {
2070 if (ec)
2071 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002072 std::string errMsg =
2073 "SIO ONCONTROL handler error: " + ec.message();
2074 phosphor::logging::log<phosphor::logging::level::ERR>(
2075 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002076 return;
2077 }
Zev Weiss584aa132021-09-02 19:21:52 -05002078 sioOnControlGPIOHandler();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002079 });
2080}
2081
Zev Weiss584aa132021-09-02 19:21:52 -05002082static void sioS5Handler(bool state)
2083{
2084 Event powerControlEvent = state ? Event::sioS5DeAssert : Event::sioS5Assert;
2085 sendPowerControlEvent(powerControlEvent);
2086}
2087
2088static void sioS5GPIOHandler()
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002089{
2090 gpiod::line_event gpioLineEvent = sioS5Line.event_read();
2091
Zev Weiss584aa132021-09-02 19:21:52 -05002092 sioS5Handler(gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002093
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002094 sioS5Event.async_wait(
2095 boost::asio::posix::stream_descriptor::wait_read,
2096 [](const boost::system::error_code ec) {
2097 if (ec)
2098 {
2099 std::string errMsg = "SIO S5 handler error: " + ec.message();
2100 phosphor::logging::log<phosphor::logging::level::ERR>(
2101 errMsg.c_str());
2102 return;
2103 }
Zev Weiss584aa132021-09-02 19:21:52 -05002104 sioS5GPIOHandler();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002105 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002106}
2107
Zev Weiss584aa132021-09-02 19:21:52 -05002108static void powerButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002109{
Zev Weiss584aa132021-09-02 19:21:52 -05002110 powerButtonIface->set_property("ButtonPressed", !state);
2111 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002112 {
2113 powerButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002114 if (!powerButtonMask)
2115 {
2116 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002117 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002118 }
2119 else
2120 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002121 phosphor::logging::log<phosphor::logging::level::INFO>(
2122 "power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002123 }
2124 }
Zev Weiss584aa132021-09-02 19:21:52 -05002125}
2126
2127static void powerButtonGPIOHandler()
2128{
2129 gpiod::line_event gpioLineEvent = powerButtonLine.event_read();
2130
2131 powerButtonHandler(gpioLineEvent.event_type ==
2132 gpiod::line_event::RISING_EDGE);
2133
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002134 powerButtonEvent.async_wait(
2135 boost::asio::posix::stream_descriptor::wait_read,
2136 [](const boost::system::error_code ec) {
2137 if (ec)
2138 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002139 std::string errMsg =
2140 "power button handler error: " + ec.message();
2141 phosphor::logging::log<phosphor::logging::level::ERR>(
2142 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002143 return;
2144 }
Zev Weiss584aa132021-09-02 19:21:52 -05002145 powerButtonGPIOHandler();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002146 });
2147}
2148
Zev Weiss584aa132021-09-02 19:21:52 -05002149static void resetButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002150{
Zev Weiss584aa132021-09-02 19:21:52 -05002151 resetButtonIface->set_property("ButtonPressed", !state);
2152 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002153 {
2154 resetButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002155 if (!resetButtonMask)
2156 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002157 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002158 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002159 }
2160 else
2161 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002162 phosphor::logging::log<phosphor::logging::level::INFO>(
2163 "reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002164 }
2165 }
Zev Weiss584aa132021-09-02 19:21:52 -05002166}
2167
2168static void resetButtonGPIOHandler()
2169{
2170 gpiod::line_event gpioLineEvent = resetButtonLine.event_read();
2171
2172 resetButtonHandler(gpioLineEvent.event_type ==
2173 gpiod::line_event::RISING_EDGE);
2174
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002175 resetButtonEvent.async_wait(
2176 boost::asio::posix::stream_descriptor::wait_read,
2177 [](const boost::system::error_code ec) {
2178 if (ec)
2179 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002180 std::string errMsg =
2181 "reset button handler error: " + ec.message();
2182 phosphor::logging::log<phosphor::logging::level::ERR>(
2183 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002184 return;
2185 }
Zev Weiss584aa132021-09-02 19:21:52 -05002186 resetButtonGPIOHandler();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002187 });
2188}
2189
Vijay Khemka04175c22020-10-09 14:28:11 -07002190#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002191static constexpr auto systemdBusname = "org.freedesktop.systemd1";
2192static constexpr auto systemdPath = "/org/freedesktop/systemd1";
2193static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
2194static constexpr auto systemTargetName = "chassis-system-reset.target";
2195
2196void systemReset()
2197{
2198 conn->async_method_call(
2199 [](boost::system::error_code ec) {
2200 if (ec)
2201 {
2202 phosphor::logging::log<phosphor::logging::level::ERR>(
2203 "Failed to call chassis system reset",
2204 phosphor::logging::entry("ERR=%s", ec.message().c_str()));
2205 }
2206 },
2207 systemdBusname, systemdPath, systemdInterface, "StartUnit",
2208 systemTargetName, "replace");
2209}
Vijay Khemka04175c22020-10-09 14:28:11 -07002210#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002211
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002212static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002213{
2214 conn->async_method_call(
2215 [](boost::system::error_code ec) {
2216 if (ec)
2217 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002218 phosphor::logging::log<phosphor::logging::level::INFO>(
2219 "failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002220 }
2221 },
Chen Yugang303bd582019-11-01 08:45:06 +08002222 "xyz.openbmc_project.Settings",
2223 "/xyz/openbmc_project/Chassis/Control/NMISource",
2224 "org.freedesktop.DBus.Properties", "Set",
2225 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
2226 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002227}
2228
2229static void nmiReset(void)
2230{
2231 static constexpr const uint8_t value = 1;
2232 const static constexpr int nmiOutPulseTimeMs = 200;
2233
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002234 phosphor::logging::log<phosphor::logging::level::INFO>("NMI out action");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002235 nmiOutLine.set_value(value);
Priyatharshan P70120512020-09-16 18:47:20 +05302236 std::string logMsg =
2237 nmiOutConfig.lineName + " set to " + std::to_string(value);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002238 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002239 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2240 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2241 // restore the NMI_OUT GPIO line back to the opposite value
2242 nmiOutLine.set_value(!value);
Priyatharshan P70120512020-09-16 18:47:20 +05302243 std::string logMsg = nmiOutConfig.lineName + " released";
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002244 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002245 if (ec)
2246 {
2247 // operation_aborted is expected if timer is canceled before
2248 // completion.
2249 if (ec != boost::asio::error::operation_aborted)
2250 {
Priyatharshan P70120512020-09-16 18:47:20 +05302251 std::string errMsg = nmiOutConfig.lineName +
2252 " async_wait failed: " + ec.message();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002253 phosphor::logging::log<phosphor::logging::level::ERR>(
2254 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002255 }
2256 }
2257 });
2258 // log to redfish
2259 nmiDiagIntLog();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002260 phosphor::logging::log<phosphor::logging::level::INFO>(
2261 "NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002262 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002263 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002264}
2265
2266static void nmiSourcePropertyMonitor(void)
2267{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002268 phosphor::logging::log<phosphor::logging::level::INFO>(
2269 "NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002270
2271 static std::unique_ptr<sdbusplus::bus::match::match> nmiSourceMatch =
2272 std::make_unique<sdbusplus::bus::match::match>(
2273 *conn,
2274 "type='signal',interface='org.freedesktop.DBus.Properties',"
Chen Yugang303bd582019-11-01 08:45:06 +08002275 "member='PropertiesChanged',arg0namespace='xyz.openbmc_project."
2276 "Chassis.Control."
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002277 "NMISource'",
2278 [](sdbusplus::message::message& msg) {
2279 std::string interfaceName;
2280 boost::container::flat_map<std::string,
2281 std::variant<bool, std::string>>
2282 propertiesChanged;
2283 std::string state;
2284 bool value = true;
2285 try
2286 {
2287 msg.read(interfaceName, propertiesChanged);
2288 if (propertiesChanged.begin()->first == "Enabled")
2289 {
2290 value =
2291 std::get<bool>(propertiesChanged.begin()->second);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002292 std::string logMsg =
2293 " NMI Enabled propertiesChanged value: " +
2294 std::to_string(value);
2295 phosphor::logging::log<phosphor::logging::level::INFO>(
2296 logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002297 nmiEnabled = value;
2298 if (nmiEnabled)
2299 {
2300 nmiReset();
2301 }
2302 }
2303 }
2304 catch (std::exception& e)
2305 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002306 phosphor::logging::log<phosphor::logging::level::ERR>(
2307 "Unable to read NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002308 return;
2309 }
2310 });
2311}
2312
2313static void setNmiSource()
2314{
2315 conn->async_method_call(
2316 [](boost::system::error_code ec) {
2317 if (ec)
2318 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002319 phosphor::logging::log<phosphor::logging::level::ERR>(
2320 "failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002321 }
2322 },
Chen Yugang303bd582019-11-01 08:45:06 +08002323 "xyz.openbmc_project.Settings",
2324 "/xyz/openbmc_project/Chassis/Control/NMISource",
2325 "org.freedesktop.DBus.Properties", "Set",
2326 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
2327 std::variant<std::string>{"xyz.openbmc_project.Chassis.Control."
2328 "NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002329 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002330 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002331}
2332
Zev Weiss584aa132021-09-02 19:21:52 -05002333static void nmiButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002334{
Zev Weiss584aa132021-09-02 19:21:52 -05002335 nmiButtonIface->set_property("ButtonPressed", !state);
2336 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002337 {
2338 nmiButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002339 if (nmiButtonMasked)
2340 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002341 phosphor::logging::log<phosphor::logging::level::INFO>(
2342 "NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002343 }
2344 else
2345 {
2346 setNmiSource();
2347 }
2348 }
Zev Weiss584aa132021-09-02 19:21:52 -05002349}
2350
2351static void nmiButtonGPIOHandler()
2352{
2353 gpiod::line_event gpioLineEvent = nmiButtonLine.event_read();
2354
2355 nmiButtonHandler(gpioLineEvent.event_type ==
2356 gpiod::line_event::RISING_EDGE);
2357
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002358 nmiButtonEvent.async_wait(
2359 boost::asio::posix::stream_descriptor::wait_read,
2360 [](const boost::system::error_code ec) {
2361 if (ec)
2362 {
2363 std::string errMsg =
2364 "NMI button handler error: " + ec.message();
2365 phosphor::logging::log<phosphor::logging::level::ERR>(
2366 errMsg.c_str());
2367 return;
2368 }
Zev Weiss584aa132021-09-02 19:21:52 -05002369 nmiButtonGPIOHandler();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002370 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002371}
2372
Zev Weiss584aa132021-09-02 19:21:52 -05002373static void idButtonHandler(bool state)
2374{
2375 idButtonIface->set_property("ButtonPressed", !state);
2376}
2377
2378static void idButtonGPIOHandler()
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002379{
2380 gpiod::line_event gpioLineEvent = idButtonLine.event_read();
2381
Zev Weiss584aa132021-09-02 19:21:52 -05002382 idButtonHandler(gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE);
2383
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002384 idButtonEvent.async_wait(
2385 boost::asio::posix::stream_descriptor::wait_read,
2386 [](const boost::system::error_code& ec) {
2387 if (ec)
2388 {
2389 std::string errMsg = "ID button handler error: " + ec.message();
2390 phosphor::logging::log<phosphor::logging::level::ERR>(
2391 errMsg.c_str());
2392 return;
2393 }
Zev Weiss584aa132021-09-02 19:21:52 -05002394 idButtonGPIOHandler();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002395 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002396}
2397
Jason M. Billsfb957332021-01-28 13:18:46 -08002398static void pltRstHandler(bool pltRst)
2399{
2400 if (pltRst)
2401 {
2402 sendPowerControlEvent(Event::pltRstDeAssert);
2403 }
2404 else
2405 {
2406 sendPowerControlEvent(Event::pltRstAssert);
2407 }
2408}
2409
2410static void hostMiscHandler(sdbusplus::message::message& msg)
2411{
2412 std::string interfaceName;
2413 boost::container::flat_map<std::string, std::variant<bool>>
2414 propertiesChanged;
2415 bool pltRst;
2416 try
2417 {
2418 msg.read(interfaceName, propertiesChanged);
2419 }
2420 catch (std::exception& e)
2421 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002422 phosphor::logging::log<phosphor::logging::level::ERR>(
2423 "Unable to read Host Misc status");
Jason M. Billsfb957332021-01-28 13:18:46 -08002424 return;
2425 }
2426 if (propertiesChanged.empty())
2427 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002428 phosphor::logging::log<phosphor::logging::level::ERR>(
2429 "ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002430 return;
2431 }
2432
2433 for (auto& [property, value] : propertiesChanged)
2434 {
2435 if (property == "ESpiPlatformReset")
2436 {
2437 bool* pltRst = std::get_if<bool>(&value);
2438 if (pltRst == nullptr)
2439 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002440 std::string errMsg = property + " property invalid";
2441 phosphor::logging::log<phosphor::logging::level::ERR>(
2442 errMsg.c_str());
Jason M. Billsfb957332021-01-28 13:18:46 -08002443 return;
2444 }
2445 pltRstHandler(*pltRst);
2446 }
2447 }
2448}
2449
Zev Weiss584aa132021-09-02 19:21:52 -05002450static void postCompleteHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002451{
Zev Weiss584aa132021-09-02 19:21:52 -05002452 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002453 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002454 sendPowerControlEvent(Event::postCompleteAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002455 osIface->set_property("OperatingSystemState", std::string("Standby"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002456 }
2457 else
2458 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002459 sendPowerControlEvent(Event::postCompleteDeAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002460 osIface->set_property("OperatingSystemState", std::string("Inactive"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002461 }
Zev Weiss584aa132021-09-02 19:21:52 -05002462}
2463
2464static void postCompleteGPIOHandler()
2465{
2466 gpiod::line_event gpioLineEvent = postCompleteLine.event_read();
2467
2468 postCompleteHandler(gpioLineEvent.event_type ==
2469 gpiod::line_event::RISING_EDGE);
2470
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002471 postCompleteEvent.async_wait(
2472 boost::asio::posix::stream_descriptor::wait_read,
2473 [](const boost::system::error_code ec) {
2474 if (ec)
2475 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002476 std::string errMsg =
2477 "POST complete handler error: " + ec.message();
2478 phosphor::logging::log<phosphor::logging::level::ERR>(
2479 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002480 return;
2481 }
Zev Weiss584aa132021-09-02 19:21:52 -05002482 postCompleteGPIOHandler();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002483 });
2484}
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302485
2486static int loadConfigValues()
2487{
2488 const std::string configFilePath =
2489 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2490 ".json";
2491 std::ifstream configFile(configFilePath.c_str());
2492 if (!configFile.is_open())
2493 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002494 phosphor::logging::log<phosphor::logging::level::ERR>(
2495 "loadConfigValues : Cannot open config path");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302496 return -1;
2497 }
Zev Weiss1aa08b22021-09-15 17:06:20 -05002498 auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302499
Priyatharshan P70120512020-09-16 18:47:20 +05302500 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302501 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002502 phosphor::logging::log<phosphor::logging::level::ERR>(
2503 "Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302504 return -1;
2505 }
Priyatharshan P70120512020-09-16 18:47:20 +05302506 auto gpios = jsonData["gpio_configs"];
2507 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302508
Priyatharshan P70120512020-09-16 18:47:20 +05302509 ConfigData* tempGpioData;
2510
2511 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302512 {
Priyatharshan P70120512020-09-16 18:47:20 +05302513 if (!gpioConfig.contains("Name"))
2514 {
2515 phosphor::logging::log<phosphor::logging::level::ERR>(
2516 "The 'Name' field must be defined in Json file");
2517 return -1;
2518 }
2519
2520 // Iterate through the powersignal map to check if the gpio json config
2521 // entry is valid
2522 std::string gpioName = gpioConfig["Name"];
2523 auto signalMapIter = powerSignalMap.find(gpioName);
2524 if (signalMapIter == powerSignalMap.end())
2525 {
2526 std::string errMsg = "Undefined Name : " + gpioName;
2527 phosphor::logging::log<phosphor::logging::level::ERR>(
2528 errMsg.c_str());
2529 return -1;
2530 }
2531
2532 // assign the power signal name to the corresponding structure reference
2533 // from map then fillup the structure with coressponding json config
2534 // value
2535 tempGpioData = signalMapIter->second;
2536 tempGpioData->name = gpioName;
2537
2538 if (!gpioConfig.contains("Type"))
2539 {
2540 phosphor::logging::log<phosphor::logging::level::ERR>(
2541 "The \'Type\' field must be defined in Json file");
2542 return -1;
2543 }
2544
2545 std::string signalType = gpioConfig["Type"];
2546 if (signalType == "GPIO")
2547 {
2548 tempGpioData->type = ConfigType::GPIO;
2549 }
2550 else if (signalType == "DBUS")
2551 {
2552 tempGpioData->type = ConfigType::DBUS;
2553 }
2554 else
2555 {
2556 std::string errMsg = "Undefined Type : " + signalType;
2557 phosphor::logging::log<phosphor::logging::level::ERR>(
2558 errMsg.c_str());
2559 return -1;
2560 }
2561
2562 if (tempGpioData->type == ConfigType::GPIO)
2563 {
2564 if (gpioConfig.contains("LineName"))
2565 {
2566 tempGpioData->lineName = gpioConfig["LineName"];
2567 }
2568 else
2569 {
2570 phosphor::logging::log<phosphor::logging::level::ERR>(
2571 "The \'LineName\' field must be defined for GPIO "
2572 "configuration");
2573 return -1;
2574 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002575 if (gpioConfig.contains("Polarity"))
2576 {
2577 std::string polarity = gpioConfig["Polarity"];
2578 if (polarity == "ActiveLow")
2579 {
2580 tempGpioData->polarity = false;
2581 }
2582 else if (polarity == "ActiveHigh")
2583 {
2584 tempGpioData->polarity = true;
2585 }
2586 else
2587 {
2588 std::string errMsg =
2589 "Polarity defined but not properly setup. Please "
2590 "only ActiveHigh or ActiveLow. Currently set to " +
2591 polarity;
2592 phosphor::logging::log<phosphor::logging::level::ERR>(
2593 errMsg.c_str());
2594 return -1;
2595 }
2596 }
2597 else
2598 {
2599 std::string errMsg =
2600 "Polarity field not found for " + tempGpioData->lineName;
2601 phosphor::logging::log<phosphor::logging::level::ERR>(
2602 errMsg.c_str());
2603 return -1;
2604 }
Priyatharshan P70120512020-09-16 18:47:20 +05302605 }
2606 else
2607 {
2608 // if dbus based gpio config is defined read and update the dbus
2609 // params corresponding to the gpio config instance
2610 for (auto& [key, dbusParamName] : dbusParams)
2611 {
2612 if (!gpios.contains(dbusParamName))
2613 {
2614 std::string errMsg =
2615 "The " + dbusParamName +
2616 "field must be defined for Dbus configuration ";
2617 phosphor::logging::log<phosphor::logging::level::ERR>(
2618 errMsg.c_str());
2619 return -1;
2620 }
2621 }
2622 tempGpioData->dbusName = gpios[dbusParams[DbusConfigType::name]];
2623 tempGpioData->path = gpios[dbusParams[DbusConfigType::path]];
2624 tempGpioData->interface =
2625 gpios[dbusParams[DbusConfigType::interface]];
2626 tempGpioData->lineName =
2627 gpios[dbusParams[DbusConfigType::property]];
2628 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302629 }
2630
Priyatharshan P70120512020-09-16 18:47:20 +05302631 // read and store the timer values from json config to Timer Map
2632 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302633 {
Priyatharshan P70120512020-09-16 18:47:20 +05302634 if (timers.contains(key.c_str()))
2635 {
2636 timerValue = timers[key.c_str()];
2637 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302638 }
2639
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302640 return 0;
2641}
Zev Weissa8f116a2021-09-01 21:08:30 -05002642
2643static bool getDbusMsgGPIOState(sdbusplus::message::message& msg,
2644 const std::string& lineName, bool& value)
2645{
2646 std::string thresholdInterface;
2647 std::string event;
2648 boost::container::flat_map<std::string, std::variant<bool>>
2649 propertiesChanged;
2650 try
2651 {
2652 msg.read(thresholdInterface, propertiesChanged);
2653 if (propertiesChanged.empty())
2654 {
2655 return false;
2656 }
2657
2658 event = propertiesChanged.begin()->first;
2659 if (event.empty() || event != lineName)
2660 {
2661 return false;
2662 }
2663
2664 value = std::get<bool>(propertiesChanged.begin()->second);
2665 return true;
2666 }
2667 catch (std::exception& e)
2668 {
2669 std::string logmsg =
2670 "exception while reading dbus property: " + lineName;
2671 phosphor::logging::log<phosphor::logging::level::ERR>(logmsg.c_str());
2672 return false;
2673 }
2674}
2675
2676static sdbusplus::bus::match::match
2677 dbusGPIOMatcher(const ConfigData& cfg, std::function<void(bool)> onMatch)
2678{
2679 auto pulseEventMatcherCallback =
2680 [&cfg, onMatch](sdbusplus::message::message& msg) {
2681 bool value = false;
2682 if (!getDbusMsgGPIOState(msg, cfg.lineName, value))
2683 {
2684 return;
2685 }
2686 onMatch(value);
2687 };
2688
2689 return sdbusplus::bus::match::match(
2690 static_cast<sdbusplus::bus::bus&>(*conn),
2691 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2692 "PropertiesChanged',arg0='" +
2693 cfg.dbusName + "'",
2694 std::move(pulseEventMatcherCallback));
2695}
2696
Priyatharshan P70120512020-09-16 18:47:20 +05302697int getProperty(ConfigData& configData)
2698{
2699 auto method = conn->new_method_call(
2700 configData.dbusName.c_str(), configData.path.c_str(),
2701 "org.freedesktop.DBus.Properties", "Get");
2702 method.append(configData.interface.c_str(), configData.lineName.c_str());
2703
2704 auto reply = conn->call(method);
2705 if (reply.is_method_error())
2706 {
2707 phosphor::logging::log<phosphor::logging::level::ERR>(
2708 "Error reading from Bus");
2709 return -1;
2710 }
2711 std::variant<int> resp;
2712 reply.read(resp);
2713 auto respValue = std::get_if<int>(&resp);
2714 if (!respValue)
2715 {
2716 phosphor::logging::log<phosphor::logging::level::ERR>(
2717 "Error reading response");
2718 return -1;
2719 }
2720 return (*respValue);
2721}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002722} // namespace power_control
2723
2724int main(int argc, char* argv[])
2725{
Lei YU92caa4c2021-02-23 16:59:25 +08002726 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05302727
2728 if (argc > 1)
2729 {
2730 node = argv[1];
2731 }
2732 std::string infoMsg =
2733 "Start Chassis power control service for host : " + node;
2734 phosphor::logging::log<phosphor::logging::level::INFO>(infoMsg.c_str());
2735
Lei YU92caa4c2021-02-23 16:59:25 +08002736 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002737
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302738 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08002739 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302740 {
Lei YU92caa4c2021-02-23 16:59:25 +08002741 std::string errMsg = "Host" + node + ": " + "Error in Parsing...";
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002742 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302743 }
Naveen Mosesec972d82021-07-16 21:19:23 +05302744 /* Currently for single host based systems additional busname is added
2745 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
2746 Going forward for single hosts the old bus name without zero numbering
2747 will be removed when all other applications adapted to the
2748 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
2749
2750 if (node == "0")
2751 {
2752 // Request all the dbus names
2753 conn->request_name(hostDbusName.c_str());
2754 conn->request_name(chassisDbusName.c_str());
2755 conn->request_name(osDbusName.c_str());
2756 conn->request_name(buttonDbusName.c_str());
2757 conn->request_name(nmiDbusName.c_str());
2758 conn->request_name(rstCauseDbusName.c_str());
2759 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302760
Zev Weissc4005bd2021-09-01 22:30:23 -05002761 hostDbusName += node;
2762 chassisDbusName += node;
2763 osDbusName += node;
2764 buttonDbusName += node;
2765 nmiDbusName += node;
2766 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002767
Priyatharshan P70120512020-09-16 18:47:20 +05302768 // Request all the dbus names
2769 conn->request_name(hostDbusName.c_str());
2770 conn->request_name(chassisDbusName.c_str());
2771 conn->request_name(osDbusName.c_str());
2772 conn->request_name(buttonDbusName.c_str());
2773 conn->request_name(nmiDbusName.c_str());
2774 conn->request_name(rstCauseDbusName.c_str());
2775
2776 if (sioPwrGoodConfig.lineName.empty() ||
2777 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05302778 {
Lei YU92caa4c2021-02-23 16:59:25 +08002779 sioEnabled = false;
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002780 phosphor::logging::log<phosphor::logging::level::INFO>(
2781 "SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05302782 }
2783
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002784 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302785 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002786 {
Zev Weiss584aa132021-09-02 19:21:52 -05002787 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKGPIOHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302788 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302789 {
2790 return -1;
2791 }
2792 }
Priyatharshan P70120512020-09-16 18:47:20 +05302793 else if (powerOkConfig.type == ConfigType::DBUS)
2794 {
2795
2796 static sdbusplus::bus::match::match powerOkEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002797 power_control::dbusGPIOMatcher(powerOkConfig, psPowerOKHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302798 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302799 else
2800 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002801 phosphor::logging::log<phosphor::logging::level::ERR>(
2802 "PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002803 return -1;
2804 }
2805
Lei YU92caa4c2021-02-23 16:59:25 +08002806 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002807 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05302808 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302809 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302810 {
Priyatharshan P70120512020-09-16 18:47:20 +05302811 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
Zev Weiss584aa132021-09-02 19:21:52 -05002812 sioPowerGoodGPIOHandler, sioPowerGoodLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302813 sioPowerGoodEvent))
2814 {
2815 return -1;
2816 }
2817 }
2818 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
2819 {
2820 static sdbusplus::bus::match::match sioPwrGoodEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002821 power_control::dbusGPIOMatcher(sioPwrGoodConfig,
2822 sioPowerGoodHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302823 }
2824 else
2825 {
2826 phosphor::logging::log<phosphor::logging::level::ERR>(
2827 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302828 return -1;
2829 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002830
Priyatharshan P19c47a32020-08-12 18:16:43 +05302831 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302832 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302833 {
Priyatharshan P70120512020-09-16 18:47:20 +05302834 if (!requestGPIOEvents(sioOnControlConfig.lineName,
Zev Weiss584aa132021-09-02 19:21:52 -05002835 sioOnControlGPIOHandler, sioOnControlLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302836 sioOnControlEvent))
2837 {
2838 return -1;
2839 }
2840 }
2841 else if (sioOnControlConfig.type == ConfigType::DBUS)
2842 {
2843 static sdbusplus::bus::match::match sioOnControlEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002844 power_control::dbusGPIOMatcher(sioOnControlConfig,
2845 sioOnControlHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302846 }
2847 else
2848 {
2849 phosphor::logging::log<phosphor::logging::level::ERR>(
2850 "sioOnControl name should be configured from json"
2851 "config file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302852 return -1;
2853 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002854
Priyatharshan P19c47a32020-08-12 18:16:43 +05302855 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302856 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302857 {
Zev Weiss584aa132021-09-02 19:21:52 -05002858 if (!requestGPIOEvents(sioS5Config.lineName, sioS5GPIOHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302859 sioS5Line, sioS5Event))
2860 {
2861 return -1;
2862 }
2863 }
2864 else if (sioS5Config.type == ConfigType::DBUS)
2865 {
2866 static sdbusplus::bus::match::match sioS5EventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002867 power_control::dbusGPIOMatcher(sioS5Config, sioS5Handler);
Priyatharshan P70120512020-09-16 18:47:20 +05302868 }
2869 else
2870 {
2871 phosphor::logging::log<phosphor::logging::level::ERR>(
2872 "sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302873 return -1;
2874 }
2875 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002876
2877 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302878 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002879 {
Zev Weiss584aa132021-09-02 19:21:52 -05002880 if (!requestGPIOEvents(powerButtonConfig.lineName,
2881 powerButtonGPIOHandler, powerButtonLine,
2882 powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302883 {
2884 return -1;
2885 }
2886 }
Priyatharshan P70120512020-09-16 18:47:20 +05302887 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302888 {
Priyatharshan P70120512020-09-16 18:47:20 +05302889 static sdbusplus::bus::match::match powerButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002890 power_control::dbusGPIOMatcher(powerButtonConfig,
2891 powerButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002892 }
2893
2894 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302895 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002896 {
Zev Weiss584aa132021-09-02 19:21:52 -05002897 if (!requestGPIOEvents(resetButtonConfig.lineName,
2898 resetButtonGPIOHandler, resetButtonLine,
2899 resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302900 {
2901 return -1;
2902 }
2903 }
Priyatharshan P70120512020-09-16 18:47:20 +05302904 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302905 {
Priyatharshan P70120512020-09-16 18:47:20 +05302906 static sdbusplus::bus::match::match resetButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002907 power_control::dbusGPIOMatcher(resetButtonConfig,
2908 resetButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002909 }
2910
2911 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302912 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302913 {
Priyatharshan P70120512020-09-16 18:47:20 +05302914 if (!nmiButtonConfig.lineName.empty())
2915 {
Zev Weiss584aa132021-09-02 19:21:52 -05002916 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonGPIOHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302917 nmiButtonLine, nmiButtonEvent);
2918 }
2919 }
2920 else if (nmiButtonConfig.type == ConfigType::DBUS)
2921 {
2922 static sdbusplus::bus::match::match nmiButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002923 power_control::dbusGPIOMatcher(nmiButtonConfig, nmiButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302924 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002925
2926 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302927 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302928 {
Priyatharshan P70120512020-09-16 18:47:20 +05302929 if (!idButtonConfig.lineName.empty())
2930 {
Zev Weiss584aa132021-09-02 19:21:52 -05002931 requestGPIOEvents(idButtonConfig.lineName, idButtonGPIOHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302932 idButtonLine, idButtonEvent);
2933 }
2934 }
2935 else if (idButtonConfig.type == ConfigType::DBUS)
2936 {
2937 static sdbusplus::bus::match::match idButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002938 power_control::dbusGPIOMatcher(idButtonConfig, idButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302939 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002940
Jason M. Billsfb957332021-01-28 13:18:46 -08002941#ifdef USE_PLT_RST
2942 sdbusplus::bus::match::match pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08002943 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08002944 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2945 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08002946 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08002947#endif
2948
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002949 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302950 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002951 {
Zev Weiss584aa132021-09-02 19:21:52 -05002952 if (!requestGPIOEvents(postCompleteConfig.lineName,
2953 postCompleteGPIOHandler, postCompleteLine,
2954 postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302955 {
2956 return -1;
2957 }
2958 }
Priyatharshan P70120512020-09-16 18:47:20 +05302959 else if (postCompleteConfig.type == ConfigType::DBUS)
2960 {
2961 static sdbusplus::bus::match::match postCompleteEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002962 power_control::dbusGPIOMatcher(postCompleteConfig,
2963 postCompleteHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302964 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302965 else
2966 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002967 phosphor::logging::log<phosphor::logging::level::ERR>(
2968 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002969 return -1;
2970 }
2971
2972 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05302973 if (!nmiOutConfig.lineName.empty())
2974 {
2975 setGPIOOutput(nmiOutConfig.lineName, 0, nmiOutLine);
2976 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002977
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002978 // Initialize POWER_OUT and RESET_OUT GPIO.
2979 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05302980 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002981 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002982 if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
2983 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302984 {
2985 return -1;
2986 }
2987 }
2988 else
2989 {
2990 phosphor::logging::log<phosphor::logging::level::ERR>(
2991 "powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002992 return -1;
2993 }
2994
Priyatharshan P70120512020-09-16 18:47:20 +05302995 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002996 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002997 if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
2998 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302999 {
3000 return -1;
3001 }
3002 }
3003 else
3004 {
3005 phosphor::logging::log<phosphor::logging::level::ERR>(
3006 "ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003007 return -1;
3008 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003009 // Release line
3010 line.reset();
3011
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003012 // Initialize the power state
Lei YU92caa4c2021-02-23 16:59:25 +08003013 powerState = PowerState::off;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003014 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05303015
3016 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003017 {
Jean-Marie Verdun61b4a5b2021-09-19 08:53:28 -04003018 if (psPowerOKLine.get_value() > 0 ||
3019 sioPowerGoodLine.get_value() == sioPwrGoodConfig.polarity)
Priyatharshan P70120512020-09-16 18:47:20 +05303020 {
3021 powerState = PowerState::on;
3022 }
3023 }
3024 else
3025 {
3026 if (getProperty(powerOkConfig))
3027 {
3028 powerState = PowerState::on;
3029 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003030 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003031 // Initialize the power state storage
Lei YU92caa4c2021-02-23 16:59:25 +08003032 if (initializePowerStateStorage() < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003033 {
3034 return -1;
3035 }
3036
3037 // Check if we need to start the Power Restore policy
Lei YU92caa4c2021-02-23 16:59:25 +08003038 powerRestorePolicyCheck();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003039
Lei YU92caa4c2021-02-23 16:59:25 +08003040 if (nmiOutLine)
3041 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003042
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003043 phosphor::logging::log<phosphor::logging::level::INFO>(
3044 "Initializing power state. ");
Lei YU92caa4c2021-02-23 16:59:25 +08003045 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003046
3047 // Power Control Service
3048 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003049 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003050
3051 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303052 hostIface =
3053 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
3054 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003055 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08003056 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003057 "RequestedHostTransition",
3058 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
3059 [](const std::string& requested, std::string& resp) {
3060 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
3061 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003062 // if power button is masked, ignore this
3063 if (!powerButtonMask)
3064 {
3065 sendPowerControlEvent(Event::gracefulPowerOffRequest);
3066 addRestartCause(RestartCause::command);
3067 }
3068 else
3069 {
3070 phosphor::logging::log<phosphor::logging::level::INFO>(
3071 "Power Button Masked.");
3072 throw std::invalid_argument("Transition Request Masked");
3073 return 0;
3074 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003075 }
3076 else if (requested ==
3077 "xyz.openbmc_project.State.Host.Transition.On")
3078 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003079 // if power button is masked, ignore this
3080 if (!powerButtonMask)
3081 {
3082 sendPowerControlEvent(Event::powerOnRequest);
3083 addRestartCause(RestartCause::command);
3084 }
3085 else
3086 {
3087 phosphor::logging::log<phosphor::logging::level::INFO>(
3088 "Power Button Masked.");
3089 throw std::invalid_argument("Transition Request Masked");
3090 return 0;
3091 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003092 }
3093 else if (requested ==
3094 "xyz.openbmc_project.State.Host.Transition.Reboot")
3095 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003096 // if power button is masked, ignore this
3097 if (!powerButtonMask)
3098 {
3099 sendPowerControlEvent(Event::powerCycleRequest);
3100 addRestartCause(RestartCause::command);
3101 }
3102 else
3103 {
3104 phosphor::logging::log<phosphor::logging::level::INFO>(
3105 "Power Button Masked.");
3106 throw std::invalid_argument("Transition Request Masked");
3107 return 0;
3108 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003109 }
3110 else if (requested == "xyz.openbmc_project.State.Host.Transition."
3111 "GracefulWarmReboot")
3112 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003113 // if reset button is masked, ignore this
3114 if (!resetButtonMask)
3115 {
3116 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
3117 addRestartCause(RestartCause::command);
3118 }
3119 else
3120 {
3121 phosphor::logging::log<phosphor::logging::level::INFO>(
3122 "Reset Button Masked.");
3123 throw std::invalid_argument("Transition Request Masked");
3124 return 0;
3125 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003126 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003127 else if (requested == "xyz.openbmc_project.State.Host.Transition."
3128 "ForceWarmReboot")
3129 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003130 // if reset button is masked, ignore this
3131 if (!resetButtonMask)
3132 {
3133 sendPowerControlEvent(Event::resetRequest);
3134 addRestartCause(RestartCause::command);
3135 }
3136 else
3137 {
3138 phosphor::logging::log<phosphor::logging::level::INFO>(
3139 "Reset Button Masked.");
3140 throw std::invalid_argument("Transition Request Masked");
3141 return 0;
3142 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003143 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003144 else
3145 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003146 phosphor::logging::log<phosphor::logging::level::ERR>(
3147 "Unrecognized host state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003148 throw std::invalid_argument("Unrecognized Transition Request");
3149 return 0;
3150 }
3151 resp = requested;
3152 return 1;
3153 });
Lei YU92caa4c2021-02-23 16:59:25 +08003154 hostIface->register_property("CurrentHostState",
3155 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003156
Lei YU92caa4c2021-02-23 16:59:25 +08003157 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003158
3159 // Chassis Control Service
3160 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003161 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003162
3163 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003164 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05303165 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003166 "xyz.openbmc_project.State.Chassis");
3167
Lei YU92caa4c2021-02-23 16:59:25 +08003168 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003169 "RequestedPowerTransition",
3170 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
3171 [](const std::string& requested, std::string& resp) {
3172 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
3173 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003174 // if power button is masked, ignore this
3175 if (!powerButtonMask)
3176 {
3177 sendPowerControlEvent(Event::powerOffRequest);
3178 addRestartCause(RestartCause::command);
3179 }
3180 else
3181 {
3182 phosphor::logging::log<phosphor::logging::level::INFO>(
3183 "Power Button Masked.");
3184 throw std::invalid_argument("Transition Request Masked");
3185 return 0;
3186 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003187 }
3188 else if (requested ==
3189 "xyz.openbmc_project.State.Chassis.Transition.On")
3190 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003191 // if power button is masked, ignore this
3192 if (!powerButtonMask)
3193 {
3194 sendPowerControlEvent(Event::powerOnRequest);
3195 addRestartCause(RestartCause::command);
3196 }
3197 else
3198 {
3199 phosphor::logging::log<phosphor::logging::level::INFO>(
3200 "Power Button Masked.");
3201 throw std::invalid_argument("Transition Request Masked");
3202 return 0;
3203 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003204 }
3205 else if (requested ==
3206 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3207 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003208 // if power button is masked, ignore this
3209 if (!powerButtonMask)
3210 {
3211 sendPowerControlEvent(Event::powerCycleRequest);
3212 addRestartCause(RestartCause::command);
3213 }
3214 else
3215 {
3216 phosphor::logging::log<phosphor::logging::level::INFO>(
3217 "Power Button Masked.");
3218 throw std::invalid_argument("Transition Request Masked");
3219 return 0;
3220 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003221 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003222 else
3223 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003224 phosphor::logging::log<phosphor::logging::level::ERR>(
3225 "Unrecognized chassis state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003226 throw std::invalid_argument("Unrecognized Transition Request");
3227 return 0;
3228 }
3229 resp = requested;
3230 return 1;
3231 });
Lei YU92caa4c2021-02-23 16:59:25 +08003232 chassisIface->register_property("CurrentPowerState",
3233 std::string(getChassisState(powerState)));
3234 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003235
Lei YU92caa4c2021-02-23 16:59:25 +08003236 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003237
Vijay Khemka04175c22020-10-09 14:28:11 -07003238#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003239 // Chassis System Service
3240 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003241 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003242
3243 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003244 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003245 "/xyz/openbmc_project/state/chassis_system0",
3246 "xyz.openbmc_project.State.Chassis");
3247
Lei YU92caa4c2021-02-23 16:59:25 +08003248 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003249 "RequestedPowerTransition",
3250 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3251 [](const std::string& requested, std::string& resp) {
3252 if (requested ==
3253 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3254 {
Lei YU92caa4c2021-02-23 16:59:25 +08003255 systemReset();
3256 addRestartCause(RestartCause::command);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003257 }
3258 else
3259 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003260 phosphor::logging::log<phosphor::logging::level::ERR>(
3261 "Unrecognized chassis system state transition request.");
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003262 throw std::invalid_argument("Unrecognized Transition Request");
3263 return 0;
3264 }
3265 resp = requested;
3266 return 1;
3267 });
Lei YU92caa4c2021-02-23 16:59:25 +08003268 chassisSysIface->register_property(
3269 "CurrentPowerState", std::string(getChassisState(powerState)));
3270 chassisSysIface->register_property("LastStateChangeTime",
3271 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003272
Lei YU92caa4c2021-02-23 16:59:25 +08003273 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003274
Naveen Moses117c34e2021-05-26 20:10:51 +05303275 if (!slotPowerConfig.lineName.empty())
3276 {
3277 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3278 {
3279 return -1;
3280 }
3281
3282 slotPowerState = SlotPowerState::off;
3283 if (slotPowerLine.get_value() > 0)
3284 {
3285 slotPowerState = SlotPowerState::on;
3286 }
3287
3288 chassisSlotIface = chassisSysServer.add_interface(
3289 "/xyz/openbmc_project/state/chassis_system" + node,
3290 "xyz.openbmc_project.State.Chassis");
3291 chassisSlotIface->register_property(
3292 "RequestedPowerTransition",
3293 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3294 [](const std::string& requested, std::string& resp) {
3295 if (requested ==
3296 "xyz.openbmc_project.State.Chassis.Transition.On")
3297 {
3298 slotPowerOn();
3299 }
3300 else if (requested ==
3301 "xyz.openbmc_project.State.Chassis.Transition.Off")
3302 {
3303 slotPowerOff();
3304 }
3305 else if (requested == "xyz.openbmc_project.State.Chassis."
3306 "Transition.PowerCycle")
3307 {
3308 slotPowerCycle();
3309 }
3310 else
3311 {
3312 phosphor::logging::log<phosphor::logging::level::ERR>(
3313 "Unrecognized chassis system state transition "
3314 "request.\n");
3315 throw std::invalid_argument(
3316 "Unrecognized Transition Request");
3317 return 0;
3318 }
3319 resp = requested;
3320 return 1;
3321 });
3322 chassisSlotIface->register_property(
3323 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3324 chassisSlotIface->register_property("LastStateChangeTime",
3325 getCurrentTimeMs());
3326 chassisSlotIface->initialize();
3327 }
3328#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003329 // Buttons Service
3330 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003331 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003332
Priyatharshan P70120512020-09-16 18:47:20 +05303333 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003334 {
Priyatharshan P70120512020-09-16 18:47:20 +05303335 // Power Button Interface
3336 power_control::powerButtonIface = buttonsServer.add_interface(
3337 "/xyz/openbmc_project/chassis/buttons/power",
3338 "xyz.openbmc_project.Chassis.Buttons");
3339
3340 powerButtonIface->register_property(
3341 "ButtonMasked", false, [](const bool requested, bool& current) {
3342 if (requested)
3343 {
3344 if (powerButtonMask)
3345 {
3346 return 1;
3347 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003348 if (!setGPIOOutput(powerOutConfig.lineName,
3349 !powerOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303350 powerButtonMask))
3351 {
3352 throw std::runtime_error("Failed to request GPIO");
3353 return 0;
3354 }
3355 phosphor::logging::log<phosphor::logging::level::INFO>(
3356 "Power Button Masked.");
3357 }
3358 else
3359 {
3360 if (!powerButtonMask)
3361 {
3362 return 1;
3363 }
3364 phosphor::logging::log<phosphor::logging::level::INFO>(
3365 "Power Button Un-masked");
3366 powerButtonMask.reset();
3367 }
3368 // Update the mask setting
3369 current = requested;
3370 return 1;
3371 });
3372
3373 // Check power button state
3374 bool powerButtonPressed;
3375 if (powerButtonConfig.type == ConfigType::GPIO)
3376 {
3377 powerButtonPressed = powerButtonLine.get_value() == 0;
3378 }
3379 else
3380 {
3381 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3382 }
3383
3384 powerButtonIface->register_property("ButtonPressed",
3385 powerButtonPressed);
3386
3387 powerButtonIface->initialize();
3388 }
3389
3390 if (!resetButtonConfig.lineName.empty())
3391 {
3392 // Reset Button Interface
3393
Lei YU92caa4c2021-02-23 16:59:25 +08003394 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003395 "/xyz/openbmc_project/chassis/buttons/reset",
3396 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003397
Lei YU92caa4c2021-02-23 16:59:25 +08003398 resetButtonIface->register_property(
John Wang6c090072020-09-30 13:32:16 +08003399 "ButtonMasked", false, [](const bool requested, bool& current) {
3400 if (requested)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003401 {
Lei YU92caa4c2021-02-23 16:59:25 +08003402 if (resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003403 {
3404 return 1;
3405 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003406 if (!setGPIOOutput(resetOutConfig.lineName,
3407 !resetOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303408 resetButtonMask))
John Wang6c090072020-09-30 13:32:16 +08003409 {
3410 throw std::runtime_error("Failed to request GPIO");
3411 return 0;
3412 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003413 phosphor::logging::log<phosphor::logging::level::INFO>(
3414 "Reset Button Masked.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003415 }
John Wang6c090072020-09-30 13:32:16 +08003416 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003417 {
Lei YU92caa4c2021-02-23 16:59:25 +08003418 if (!resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003419 {
3420 return 1;
3421 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003422 phosphor::logging::log<phosphor::logging::level::INFO>(
3423 "Reset Button Un-masked");
Lei YU92caa4c2021-02-23 16:59:25 +08003424 resetButtonMask.reset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003425 }
John Wang6c090072020-09-30 13:32:16 +08003426 // Update the mask setting
3427 current = requested;
3428 return 1;
3429 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003430
John Wang6c090072020-09-30 13:32:16 +08003431 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303432 bool resetButtonPressed;
3433 if (resetButtonConfig.type == ConfigType::GPIO)
3434 {
3435 resetButtonPressed = resetButtonLine.get_value() == 0;
3436 }
3437 else
3438 {
3439 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3440 }
3441
Lei YU92caa4c2021-02-23 16:59:25 +08003442 resetButtonIface->register_property("ButtonPressed",
3443 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003444
Lei YU92caa4c2021-02-23 16:59:25 +08003445 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003446 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003447
Lei YU92caa4c2021-02-23 16:59:25 +08003448 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003449 {
3450 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003451 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003452 "/xyz/openbmc_project/chassis/buttons/nmi",
3453 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003454
Lei YU92caa4c2021-02-23 16:59:25 +08003455 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003456 "ButtonMasked", false, [](const bool requested, bool& current) {
Lei YU92caa4c2021-02-23 16:59:25 +08003457 if (nmiButtonMasked == requested)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003458 {
3459 // NMI button mask is already set as requested, so no change
3460 return 1;
3461 }
3462 if (requested)
3463 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003464 phosphor::logging::log<phosphor::logging::level::INFO>(
3465 "NMI Button Masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003466 nmiButtonMasked = true;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003467 }
3468 else
3469 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003470 phosphor::logging::log<phosphor::logging::level::INFO>(
3471 "NMI Button Un-masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003472 nmiButtonMasked = false;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003473 }
3474 // Update the mask setting
Lei YU92caa4c2021-02-23 16:59:25 +08003475 current = nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003476 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003477 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003478
Vijay Khemka33a532d2019-11-14 16:50:35 -08003479 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303480 bool nmiButtonPressed;
3481 if (nmiButtonConfig.type == ConfigType::GPIO)
3482 {
3483 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3484 }
3485 else
3486 {
3487 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3488 }
3489
Lei YU92caa4c2021-02-23 16:59:25 +08003490 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003491
Lei YU92caa4c2021-02-23 16:59:25 +08003492 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003493 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003494
Lei YU92caa4c2021-02-23 16:59:25 +08003495 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003496 {
3497 // NMI out Service
3498 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003499 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003500
Vijay Khemka33a532d2019-11-14 16:50:35 -08003501 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303502 nmiOutIface = nmiOutServer.add_interface(
3503 "/xyz/openbmc_project/control/host" + node + "/nmi",
3504 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003505 nmiOutIface->register_method("NMI", nmiReset);
3506 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003507 }
Chen Yugang174ec662019-08-19 19:58:49 +08003508
Lei YU92caa4c2021-02-23 16:59:25 +08003509 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003510 {
3511 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003512 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003513 "/xyz/openbmc_project/chassis/buttons/id",
3514 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003515
Vijay Khemka33a532d2019-11-14 16:50:35 -08003516 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303517 bool idButtonPressed;
3518 if (idButtonConfig.type == ConfigType::GPIO)
3519 {
3520 idButtonPressed = idButtonLine.get_value() == 0;
3521 }
3522 else
3523 {
3524 idButtonPressed = getProperty(idButtonConfig) == 0;
3525 }
3526
Lei YU92caa4c2021-02-23 16:59:25 +08003527 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003528
Lei YU92caa4c2021-02-23 16:59:25 +08003529 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003530 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003531
3532 // OS State Service
3533 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003534 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003535
3536 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003537 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003538 "/xyz/openbmc_project/state/os",
3539 "xyz.openbmc_project.State.OperatingSystem.Status");
3540
3541 // Get the initial OS state based on POST complete
3542 // 0: Asserted, OS state is "Standby" (ready to boot)
3543 // 1: De-Asserted, OS state is "Inactive"
Priyatharshan P70120512020-09-16 18:47:20 +05303544 std::string osState;
3545 if (postCompleteConfig.type == ConfigType::GPIO)
3546 {
3547 osState = postCompleteLine.get_value() > 0 ? "Inactive" : "Standby";
3548 }
3549 else
3550 {
3551 osState = getProperty(postCompleteConfig) > 0 ? "Inactive" : "Standby";
3552 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003553
Lei YU92caa4c2021-02-23 16:59:25 +08003554 osIface->register_property("OperatingSystemState", std::string(osState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003555
Lei YU92caa4c2021-02-23 16:59:25 +08003556 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003557
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003558 // Restart Cause Service
3559 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003560 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003561
3562 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003563 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303564 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003565 "xyz.openbmc_project.Control.Host.RestartCause");
3566
Lei YU92caa4c2021-02-23 16:59:25 +08003567 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003568 "RestartCause",
3569 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3570
Lei YU92caa4c2021-02-23 16:59:25 +08003571 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003572 "RequestedRestartCause",
3573 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3574 [](const std::string& requested, std::string& resp) {
3575 if (requested ==
3576 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3577 {
Lei YU92caa4c2021-02-23 16:59:25 +08003578 addRestartCause(RestartCause::watchdog);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003579 }
3580 else
3581 {
3582 throw std::invalid_argument(
3583 "Unrecognized RestartCause Request");
3584 return 0;
3585 }
3586
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003587 std::string logMsg = "RestartCause requested: " + requested;
3588 phosphor::logging::log<phosphor::logging::level::INFO>(
3589 logMsg.c_str());
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003590 resp = requested;
3591 return 1;
3592 });
3593
Lei YU92caa4c2021-02-23 16:59:25 +08003594 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003595
Lei YU92caa4c2021-02-23 16:59:25 +08003596 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003597
Lei YU92caa4c2021-02-23 16:59:25 +08003598 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003599
3600 return 0;
3601}