blob: 733cfb1af25b21cd2d50b03a81c33923c220a136 [file] [log] [blame]
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001/*
2// Copyright (c) 2018-2019 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#include "i2c.hpp"
17
18#include <sys/sysinfo.h>
19#include <systemd/sd-journal.h>
20
Jason M. Billse63dea02020-08-27 12:07:35 -070021#include <boost/asio/io_service.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070022#include <boost/asio/posix/stream_descriptor.hpp>
Jason M. Billse63dea02020-08-27 12:07:35 -070023#include <boost/asio/steady_timer.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070024#include <boost/container/flat_map.hpp>
Jason M. Bills7d4aaac2019-09-19 14:03:44 -070025#include <boost/container/flat_set.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070026#include <gpiod.hpp>
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053027#include <nlohmann/json.hpp>
Vijay Khemkafc1ecc52020-04-01 10:49:28 -070028#include <phosphor-logging/log.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070029#include <sdbusplus/asio/object_server.hpp>
Vijay Khemka2b6f4422020-05-29 11:13:23 -070030
31#include <filesystem>
32#include <fstream>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070033#include <string_view>
34
35namespace power_control
36{
37static boost::asio::io_service io;
38std::shared_ptr<sdbusplus::asio::connection> conn;
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053039
40static std::string node = "0";
41
Priyatharshan P70120512020-09-16 18:47:20 +053042enum class DbusConfigType
43{
44 name = 1,
45 path,
46 interface,
47 property
48};
49boost::container::flat_map<DbusConfigType, std::string> dbusParams = {
50 {DbusConfigType::name, "DbusName"},
51 {DbusConfigType::path, "Path"},
52 {DbusConfigType::interface, "Interface"},
53 {DbusConfigType::property, "Property"}};
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053054
Priyatharshan P70120512020-09-16 18:47:20 +053055enum class ConfigType
56{
57 GPIO = 1,
58 DBUS
59};
60
61struct ConfigData
62{
63 std::string name;
64 std::string lineName;
65 std::string dbusName;
66 std::string path;
67 std::string interface;
Jean-Marie Verdun50937e72021-08-31 09:15:49 -070068 bool polarity;
Priyatharshan P70120512020-09-16 18:47:20 +053069 ConfigType type;
70};
71
72static ConfigData powerOutConfig;
73static ConfigData powerOkConfig;
74static ConfigData resetOutConfig;
75static ConfigData nmiOutConfig;
76static ConfigData sioPwrGoodConfig;
77static ConfigData sioOnControlConfig;
78static ConfigData sioS5Config;
79static ConfigData postCompleteConfig;
80static ConfigData powerButtonConfig;
81static ConfigData resetButtonConfig;
82static ConfigData idButtonConfig;
83static ConfigData nmiButtonConfig;
Naveen Moses117c34e2021-05-26 20:10:51 +053084static ConfigData slotPowerConfig;
85
Priyatharshan P70120512020-09-16 18:47:20 +053086// map for storing list of gpio parameters whose config are to be read from x86
87// power control json config
88boost::container::flat_map<std::string, ConfigData*> powerSignalMap = {
89 {"PowerOut", &powerOutConfig},
90 {"PowerOk", &powerOkConfig},
91 {"ResetOut", &resetOutConfig},
92 {"NMIOut", &nmiOutConfig},
93 {"SioPowerGood", &sioPwrGoodConfig},
94 {"SioOnControl", &sioOnControlConfig},
95 {"SIOS5", &sioS5Config},
96 {"PostComplete", &postCompleteConfig},
97 {"PowerButton", &powerButtonConfig},
98 {"ResetButton", &resetButtonConfig},
99 {"IdButton", &idButtonConfig},
Naveen Moses117c34e2021-05-26 20:10:51 +0530100 {"NMIButton", &nmiButtonConfig},
101 {"SlotPower", &slotPowerConfig}};
Priyatharshan P70120512020-09-16 18:47:20 +0530102
103static std::string hostDbusName = "xyz.openbmc_project.State.Host";
104static std::string chassisDbusName = "xyz.openbmc_project.State.Chassis";
105static std::string osDbusName = "xyz.openbmc_project.State.OperatingSystem";
106static std::string buttonDbusName = "xyz.openbmc_project.Chassis.Buttons";
107static std::string nmiDbusName = "xyz.openbmc_project.Control.Host.NMI";
108static std::string rstCauseDbusName =
109 "xyz.openbmc_project.Control.Host.RestartCause";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700110static std::shared_ptr<sdbusplus::asio::dbus_interface> hostIface;
111static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700112#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -0700113static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSysIface;
Naveen Moses117c34e2021-05-26 20:10:51 +0530114static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSlotIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700115#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700116static std::shared_ptr<sdbusplus::asio::dbus_interface> powerButtonIface;
117static std::shared_ptr<sdbusplus::asio::dbus_interface> resetButtonIface;
118static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiButtonIface;
119static std::shared_ptr<sdbusplus::asio::dbus_interface> osIface;
120static std::shared_ptr<sdbusplus::asio::dbus_interface> idButtonIface;
Chen Yugang174ec662019-08-19 19:58:49 +0800121static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiOutIface;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700122static std::shared_ptr<sdbusplus::asio::dbus_interface> restartCauseIface;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700123
124static gpiod::line powerButtonMask;
125static gpiod::line resetButtonMask;
126static bool nmiButtonMasked = false;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700127
Priyatharshan P70120512020-09-16 18:47:20 +0530128// This map contains all timer values that are to be read from json config
129boost::container::flat_map<std::string, int> TimerMap = {
130 {"powerPulseTimeMs", 200},
131 {"forceOffPulseTimeMs", 15000},
132 {"resetPulseTimeMs", 500},
133 {"powerCycleTimeMs", 5000},
134 {"sioPowerGoodWatchdogTimeMs", 1000},
135 {"psPowerOKWatchdogTimeMs", 8000},
136 {"gracefulPowerOffTimeS", (5 * 60)},
137 {"warmResetCheckTimeMs", 500},
Naveen Moses117c34e2021-05-26 20:10:51 +0530138 {"powerOffSaveTimeMs", 7000},
139 {"slotPowerCycleTimeMs", 200}};
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700140const static std::filesystem::path powerControlDir = "/var/lib/power-control";
141const static constexpr std::string_view powerStateFile = "power-state";
142
143static bool nmiEnabled = true;
Priyatharshan P19c47a32020-08-12 18:16:43 +0530144static bool sioEnabled = true;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700145
146// Timers
147// Time holding GPIOs asserted
148static boost::asio::steady_timer gpioAssertTimer(io);
149// Time between off and on during a power cycle
150static boost::asio::steady_timer powerCycleTimer(io);
151// Time OS gracefully powering off
152static boost::asio::steady_timer gracefulPowerOffTimer(io);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700153// Time the warm reset check
154static boost::asio::steady_timer warmResetCheckTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700155// Time power supply power OK assertion on power-on
156static boost::asio::steady_timer psPowerOKWatchdogTimer(io);
157// Time SIO power good assertion on power-on
158static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io);
159// Time power-off state save for power loss tracking
160static boost::asio::steady_timer powerStateSaveTimer(io);
161// POH timer
162static boost::asio::steady_timer pohCounterTimer(io);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700163// Time when to allow restart cause updates
164static boost::asio::steady_timer restartCauseTimer(io);
Naveen Moses117c34e2021-05-26 20:10:51 +0530165static boost::asio::steady_timer slotPowerCycleTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700166
167// GPIO Lines and Event Descriptors
168static gpiod::line psPowerOKLine;
169static boost::asio::posix::stream_descriptor psPowerOKEvent(io);
170static gpiod::line sioPowerGoodLine;
171static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io);
172static gpiod::line sioOnControlLine;
173static boost::asio::posix::stream_descriptor sioOnControlEvent(io);
174static gpiod::line sioS5Line;
175static boost::asio::posix::stream_descriptor sioS5Event(io);
176static gpiod::line powerButtonLine;
177static boost::asio::posix::stream_descriptor powerButtonEvent(io);
178static gpiod::line resetButtonLine;
179static boost::asio::posix::stream_descriptor resetButtonEvent(io);
180static gpiod::line nmiButtonLine;
181static boost::asio::posix::stream_descriptor nmiButtonEvent(io);
182static gpiod::line idButtonLine;
183static boost::asio::posix::stream_descriptor idButtonEvent(io);
184static gpiod::line postCompleteLine;
185static boost::asio::posix::stream_descriptor postCompleteEvent(io);
186static gpiod::line nmiOutLine;
Naveen Moses117c34e2021-05-26 20:10:51 +0530187static gpiod::line slotPowerLine;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700188
189static constexpr uint8_t beepPowerFail = 8;
190
191static void beep(const uint8_t& beepPriority)
192{
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800193 std::string logMsg = "Beep with priority: " + std::to_string(beepPriority);
194 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700195
196 conn->async_method_call(
197 [](boost::system::error_code ec) {
198 if (ec)
199 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800200 std::string errMsg =
201 "beep returned error with async_method_call (ec = " +
202 ec.message();
203 phosphor::logging::log<phosphor::logging::level::ERR>(
204 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700205 return;
206 }
207 },
208 "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
209 "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
210}
211
212enum class PowerState
213{
214 on,
215 waitForPSPowerOK,
216 waitForSIOPowerGood,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700217 off,
218 transitionToOff,
219 gracefulTransitionToOff,
220 cycleOff,
221 transitionToCycleOff,
222 gracefulTransitionToCycleOff,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700223 checkForWarmReset,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700224};
225static PowerState powerState;
226static std::string getPowerStateName(PowerState state)
227{
228 switch (state)
229 {
230 case PowerState::on:
231 return "On";
232 break;
233 case PowerState::waitForPSPowerOK:
234 return "Wait for Power Supply Power OK";
235 break;
236 case PowerState::waitForSIOPowerGood:
237 return "Wait for SIO Power Good";
238 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700239 case PowerState::off:
240 return "Off";
241 break;
242 case PowerState::transitionToOff:
243 return "Transition to Off";
244 break;
245 case PowerState::gracefulTransitionToOff:
246 return "Graceful Transition to Off";
247 break;
248 case PowerState::cycleOff:
249 return "Power Cycle Off";
250 break;
251 case PowerState::transitionToCycleOff:
252 return "Transition to Power Cycle Off";
253 break;
254 case PowerState::gracefulTransitionToCycleOff:
255 return "Graceful Transition to Power Cycle Off";
256 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700257 case PowerState::checkForWarmReset:
258 return "Check for Warm Reset";
259 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700260 default:
261 return "unknown state: " + std::to_string(static_cast<int>(state));
262 break;
263 }
264}
265static void logStateTransition(const PowerState state)
266{
Naveen Mosesec972d82021-07-16 21:19:23 +0530267 std::string logMsg = "Host" + node + ": Moving to \"" +
268 getPowerStateName(state) + "\" state";
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700269 phosphor::logging::log<phosphor::logging::level::INFO>(
270 logMsg.c_str(),
Vijay Khemkad6c5ad12020-05-27 14:57:52 -0700271 phosphor::logging::entry("STATE=%s", getPowerStateName(state).c_str()),
Naveen Mosesec972d82021-07-16 21:19:23 +0530272 phosphor::logging::entry("HOST=%s", node.c_str()));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700273}
274
275enum class Event
276{
277 psPowerOKAssert,
278 psPowerOKDeAssert,
279 sioPowerGoodAssert,
280 sioPowerGoodDeAssert,
281 sioS5Assert,
282 sioS5DeAssert,
Jason M. Billsfb957332021-01-28 13:18:46 -0800283 pltRstAssert,
284 pltRstDeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700285 postCompleteAssert,
286 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700287 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700288 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700289 powerCycleTimerExpired,
290 psPowerOKWatchdogTimerExpired,
291 sioPowerGoodWatchdogTimerExpired,
292 gracefulPowerOffTimerExpired,
293 powerOnRequest,
294 powerOffRequest,
295 powerCycleRequest,
296 resetRequest,
297 gracefulPowerOffRequest,
298 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700299 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700300};
301static std::string getEventName(Event event)
302{
303 switch (event)
304 {
305 case Event::psPowerOKAssert:
306 return "power supply power OK assert";
307 break;
308 case Event::psPowerOKDeAssert:
309 return "power supply power OK de-assert";
310 break;
311 case Event::sioPowerGoodAssert:
312 return "SIO power good assert";
313 break;
314 case Event::sioPowerGoodDeAssert:
315 return "SIO power good de-assert";
316 break;
317 case Event::sioS5Assert:
318 return "SIO S5 assert";
319 break;
320 case Event::sioS5DeAssert:
321 return "SIO S5 de-assert";
322 break;
Jason M. Billsfb957332021-01-28 13:18:46 -0800323 case Event::pltRstAssert:
324 return "PLT_RST assert";
325 break;
326 case Event::pltRstDeAssert:
327 return "PLT_RST de-assert";
328 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700329 case Event::postCompleteAssert:
330 return "POST Complete assert";
331 break;
332 case Event::postCompleteDeAssert:
333 return "POST Complete de-assert";
334 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700335 case Event::powerButtonPressed:
336 return "power button pressed";
337 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700338 case Event::resetButtonPressed:
339 return "reset button pressed";
340 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700341 case Event::powerCycleTimerExpired:
342 return "power cycle timer expired";
343 break;
344 case Event::psPowerOKWatchdogTimerExpired:
345 return "power supply power OK watchdog timer expired";
346 break;
347 case Event::sioPowerGoodWatchdogTimerExpired:
348 return "SIO power good watchdog timer expired";
349 break;
350 case Event::gracefulPowerOffTimerExpired:
351 return "graceful power-off timer expired";
352 break;
353 case Event::powerOnRequest:
354 return "power-on request";
355 break;
356 case Event::powerOffRequest:
357 return "power-off request";
358 break;
359 case Event::powerCycleRequest:
360 return "power-cycle request";
361 break;
362 case Event::resetRequest:
363 return "reset request";
364 break;
365 case Event::gracefulPowerOffRequest:
366 return "graceful power-off request";
367 break;
368 case Event::gracefulPowerCycleRequest:
369 return "graceful power-cycle request";
370 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700371 case Event::warmResetDetected:
372 return "warm reset detected";
373 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700374 default:
375 return "unknown event: " + std::to_string(static_cast<int>(event));
376 break;
377 }
378}
379static void logEvent(const std::string_view stateHandler, const Event event)
380{
Vijay Khemkafc1ecc52020-04-01 10:49:28 -0700381 std::string logMsg{stateHandler};
382 logMsg += ": " + getEventName(event) + " event received";
383 phosphor::logging::log<phosphor::logging::level::INFO>(
384 logMsg.c_str(),
385 phosphor::logging::entry("EVENT=%s", getEventName(event).c_str()));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700386}
387
388// Power state handlers
389static void powerStateOn(const Event event);
390static void powerStateWaitForPSPowerOK(const Event event);
391static void powerStateWaitForSIOPowerGood(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700392static void powerStateOff(const Event event);
393static void powerStateTransitionToOff(const Event event);
394static void powerStateGracefulTransitionToOff(const Event event);
395static void powerStateCycleOff(const Event event);
396static void powerStateTransitionToCycleOff(const Event event);
397static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700398static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700399
400static std::function<void(const Event)> getPowerStateHandler(PowerState state)
401{
402 switch (state)
403 {
404 case PowerState::on:
405 return powerStateOn;
406 break;
407 case PowerState::waitForPSPowerOK:
408 return powerStateWaitForPSPowerOK;
409 break;
410 case PowerState::waitForSIOPowerGood:
411 return powerStateWaitForSIOPowerGood;
412 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700413 case PowerState::off:
414 return powerStateOff;
415 break;
416 case PowerState::transitionToOff:
417 return powerStateTransitionToOff;
418 break;
419 case PowerState::gracefulTransitionToOff:
420 return powerStateGracefulTransitionToOff;
421 break;
422 case PowerState::cycleOff:
423 return powerStateCycleOff;
424 break;
425 case PowerState::transitionToCycleOff:
426 return powerStateTransitionToCycleOff;
427 break;
428 case PowerState::gracefulTransitionToCycleOff:
429 return powerStateGracefulTransitionToCycleOff;
430 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700431 case PowerState::checkForWarmReset:
432 return powerStateCheckForWarmReset;
433 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700434 default:
Zev Weiss047bcb52020-08-20 21:28:11 +0000435 return nullptr;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700436 break;
437 }
438};
439
440static void sendPowerControlEvent(const Event event)
441{
442 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
443 if (handler == nullptr)
444 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800445 std::string errMsg = "Failed to find handler for power state: " +
446 std::to_string(static_cast<int>(powerState));
447 phosphor::logging::log<phosphor::logging::level::INFO>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700448 return;
449 }
450 handler(event);
451}
452
453static uint64_t getCurrentTimeMs()
454{
455 struct timespec time = {};
456
457 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
458 {
459 return 0;
460 }
461 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
462 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
463
464 return currentTimeMs;
465}
466
467static constexpr std::string_view getHostState(const PowerState state)
468{
469 switch (state)
470 {
471 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700472 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700473 case PowerState::gracefulTransitionToCycleOff:
474 return "xyz.openbmc_project.State.Host.HostState.Running";
475 break;
476 case PowerState::waitForPSPowerOK:
477 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700478 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700479 case PowerState::transitionToOff:
480 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700481 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700482 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700483 return "xyz.openbmc_project.State.Host.HostState.Off";
484 break;
485 default:
486 return "";
487 break;
488 }
489};
490static constexpr std::string_view getChassisState(const PowerState state)
491{
492 switch (state)
493 {
494 case PowerState::on:
495 case PowerState::transitionToOff:
496 case PowerState::gracefulTransitionToOff:
497 case PowerState::transitionToCycleOff:
498 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700499 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700500 return "xyz.openbmc_project.State.Chassis.PowerState.On";
501 break;
502 case PowerState::waitForPSPowerOK:
503 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700504 case PowerState::off:
505 case PowerState::cycleOff:
506 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
507 break;
508 default:
509 return "";
510 break;
511 }
512};
Naveen Moses117c34e2021-05-26 20:10:51 +0530513#ifdef CHASSIS_SYSTEM_RESET
514enum class SlotPowerState
515{
516 on,
517 off,
518};
519static SlotPowerState slotPowerState;
520static constexpr std::string_view getSlotState(const SlotPowerState state)
521{
522 switch (state)
523 {
524 case SlotPowerState::on:
525 return "xyz.openbmc_project.State.Chassis.PowerState.On";
526 break;
527 case SlotPowerState::off:
528 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
529 break;
530 default:
531 return "";
532 break;
533 }
534};
535static void setSlotPowerState(const SlotPowerState state)
536{
537 slotPowerState = state;
538 chassisSlotIface->set_property("CurrentPowerState",
539 std::string(getSlotState(slotPowerState)));
540 chassisSlotIface->set_property("LastStateChangeTime", getCurrentTimeMs());
541}
542#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700543static void savePowerState(const PowerState state)
544{
545 powerStateSaveTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +0530546 std::chrono::milliseconds(TimerMap["powerOffSaveTimeMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700547 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
548 if (ec)
549 {
550 // operation_aborted is expected if timer is canceled before
551 // completion.
552 if (ec != boost::asio::error::operation_aborted)
553 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800554 std::string errMsg =
555 "Power-state save async_wait failed: " + ec.message();
556 phosphor::logging::log<phosphor::logging::level::ERR>(
557 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700558 }
559 return;
560 }
561 std::ofstream powerStateStream(powerControlDir / powerStateFile);
562 powerStateStream << getChassisState(state);
563 });
564}
565static void setPowerState(const PowerState state)
566{
567 powerState = state;
568 logStateTransition(state);
569
570 hostIface->set_property("CurrentHostState",
571 std::string(getHostState(powerState)));
572
573 chassisIface->set_property("CurrentPowerState",
574 std::string(getChassisState(powerState)));
575 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
576
577 // Save the power state for the restore policy
578 savePowerState(state);
579}
580
581enum class RestartCause
582{
583 command,
584 resetButton,
585 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700586 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700587 powerPolicyOn,
588 powerPolicyRestore,
589 softReset,
590};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700591static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700592static std::string getRestartCause(RestartCause cause)
593{
594 switch (cause)
595 {
596 case RestartCause::command:
597 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
598 break;
599 case RestartCause::resetButton:
600 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
601 break;
602 case RestartCause::powerButton:
603 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
604 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700605 case RestartCause::watchdog:
606 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
607 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700608 case RestartCause::powerPolicyOn:
609 return "xyz.openbmc_project.State.Host.RestartCause."
610 "PowerPolicyAlwaysOn";
611 break;
612 case RestartCause::powerPolicyRestore:
613 return "xyz.openbmc_project.State.Host.RestartCause."
614 "PowerPolicyPreviousState";
615 break;
616 case RestartCause::softReset:
617 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
618 break;
619 default:
620 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
621 break;
622 }
623}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700624static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700625{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700626 // Add this to the set of causes for this restart
627 causeSet.insert(cause);
628}
629static void clearRestartCause()
630{
631 // Clear the set for the next restart
632 causeSet.clear();
633}
634static void setRestartCauseProperty(const std::string& cause)
635{
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800636 std::string logMsg = "RestartCause set to " + cause;
637 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700638 restartCauseIface->set_property("RestartCause", cause);
639}
Rashmi RV89f61312020-01-22 15:41:50 +0530640
641static void resetACBootProperty()
642{
643 if ((causeSet.contains(RestartCause::command)) ||
644 (causeSet.contains(RestartCause::softReset)))
645 {
646 conn->async_method_call(
647 [](boost::system::error_code ec) {
648 if (ec)
649 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800650 phosphor::logging::log<phosphor::logging::level::ERR>(
651 "failed to reset ACBoot property");
Rashmi RV89f61312020-01-22 15:41:50 +0530652 }
653 },
654 "xyz.openbmc_project.Settings",
655 "/xyz/openbmc_project/control/host0/ac_boot",
656 "org.freedesktop.DBus.Properties", "Set",
657 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
658 std::variant<std::string>{"False"});
659 }
660}
661
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700662static void setRestartCause()
663{
664 // Determine the actual restart cause based on the set of causes
665 std::string restartCause =
666 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
667 if (causeSet.contains(RestartCause::watchdog))
668 {
669 restartCause = getRestartCause(RestartCause::watchdog);
670 }
671 else if (causeSet.contains(RestartCause::command))
672 {
673 restartCause = getRestartCause(RestartCause::command);
674 }
675 else if (causeSet.contains(RestartCause::resetButton))
676 {
677 restartCause = getRestartCause(RestartCause::resetButton);
678 }
679 else if (causeSet.contains(RestartCause::powerButton))
680 {
681 restartCause = getRestartCause(RestartCause::powerButton);
682 }
683 else if (causeSet.contains(RestartCause::powerPolicyOn))
684 {
685 restartCause = getRestartCause(RestartCause::powerPolicyOn);
686 }
687 else if (causeSet.contains(RestartCause::powerPolicyRestore))
688 {
689 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
690 }
691 else if (causeSet.contains(RestartCause::softReset))
692 {
693 restartCause = getRestartCause(RestartCause::softReset);
694 }
695
696 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700697}
698
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700699static void systemPowerGoodFailedLog()
700{
701 sd_journal_send(
702 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
703 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
704 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Priyatharshan P70120512020-09-16 18:47:20 +0530705 TimerMap["sioPowerGoodWatchdogTimeMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700706}
707
708static void psPowerOKFailedLog()
709{
710 sd_journal_send(
711 "MESSAGE=PowerControl: power supply power good failed to assert",
712 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
713 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Priyatharshan P70120512020-09-16 18:47:20 +0530714 TimerMap["psPowerOKWatchdogTimeMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700715}
716
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700717static void powerRestorePolicyLog()
718{
719 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
720 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
721 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
722}
723
724static void powerButtonPressLog()
725{
726 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
727 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
728 "OpenBMC.0.1.PowerButtonPressed", NULL);
729}
730
731static void resetButtonPressLog()
732{
733 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
734 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
735 "OpenBMC.0.1.ResetButtonPressed", NULL);
736}
737
738static void nmiButtonPressLog()
739{
740 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
741 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
742 "OpenBMC.0.1.NMIButtonPressed", NULL);
743}
744
745static void nmiDiagIntLog()
746{
747 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
748 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
749 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
750}
751
752static int initializePowerStateStorage()
753{
754 // create the power control directory if it doesn't exist
755 std::error_code ec;
756 if (!(std::filesystem::create_directories(powerControlDir, ec)))
757 {
758 if (ec.value() != 0)
759 {
Zev Weiss6b8e3e02021-09-01 22:36:03 -0500760 std::string errMsg = "failed to create " +
761 powerControlDir.string() + ": " + ec.message();
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800762 phosphor::logging::log<phosphor::logging::level::ERR>(
763 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700764 return -1;
765 }
766 }
767 // Create the power state file if it doesn't exist
768 if (!std::filesystem::exists(powerControlDir / powerStateFile))
769 {
770 std::ofstream powerStateStream(powerControlDir / powerStateFile);
771 powerStateStream << getChassisState(powerState);
772 }
773 return 0;
774}
775
776static bool wasPowerDropped()
777{
778 std::ifstream powerStateStream(powerControlDir / powerStateFile);
779 if (!powerStateStream.is_open())
780 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800781 phosphor::logging::log<phosphor::logging::level::ERR>(
782 "Failed to open power state file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700783 return false;
784 }
785
786 std::string state;
787 std::getline(powerStateStream, state);
788 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
789}
790
791static void invokePowerRestorePolicy(const std::string& policy)
792{
793 // Async events may call this twice, but we only want to run once
794 static bool policyInvoked = false;
795 if (policyInvoked)
796 {
797 return;
798 }
799 policyInvoked = true;
800
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800801 std::string logMsg = "Power restore delay expired, invoking " + policy;
802 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700803 if (policy ==
804 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
805 {
806 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700807 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700808 }
809 else if (policy == "xyz.openbmc_project.Control.Power.RestorePolicy."
810 "Policy.Restore")
811 {
812 if (wasPowerDropped())
813 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800814 phosphor::logging::log<phosphor::logging::level::INFO>(
815 "Power was dropped, restoring Host On state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700816 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700817 setRestartCauseProperty(
818 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700819 }
820 else
821 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800822 phosphor::logging::log<phosphor::logging::level::INFO>(
823 "No power drop, restoring Host Off state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700824 }
825 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -0700826 // We're done with the previous power state for the restore policy, so store
827 // the current state
828 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700829}
830
831static void powerRestorePolicyDelay(int delay)
832{
833 // Async events may call this twice, but we only want to run once
834 static bool delayStarted = false;
835 if (delayStarted)
836 {
837 return;
838 }
839 delayStarted = true;
840 // Calculate the delay from now to meet the requested delay
841 // Subtract the approximate uboot time
842 static constexpr const int ubootSeconds = 20;
843 delay -= ubootSeconds;
844 // Subtract the time since boot
845 struct sysinfo info = {};
846 if (sysinfo(&info) == 0)
847 {
848 delay -= info.uptime;
849 }
850 // 0 is the minimum delay
851 delay = std::max(delay, 0);
852
853 static boost::asio::steady_timer powerRestorePolicyTimer(io);
854 powerRestorePolicyTimer.expires_after(std::chrono::seconds(delay));
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800855 std::string logMsg =
856 "Power restore delay of " + std::to_string(delay) + " seconds started";
857 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700858 powerRestorePolicyTimer.async_wait([](const boost::system::error_code ec) {
859 if (ec)
860 {
861 // operation_aborted is expected if timer is canceled before
862 // completion.
863 if (ec != boost::asio::error::operation_aborted)
864 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800865 std::string errMsg =
866 "power restore policy async_wait failed: " + ec.message();
867 phosphor::logging::log<phosphor::logging::level::ERR>(
868 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700869 }
870 return;
871 }
872 // Get Power Restore Policy
873 // In case PowerRestorePolicy is not available, set a match for it
874 static std::unique_ptr<sdbusplus::bus::match::match>
875 powerRestorePolicyMatch = std::make_unique<
876 sdbusplus::bus::match::match>(
877 *conn,
878 "type='signal',interface='org.freedesktop.DBus.Properties',"
879 "member='PropertiesChanged',arg0namespace='xyz.openbmc_"
880 "project.Control.Power.RestorePolicy'",
881 [](sdbusplus::message::message& msg) {
882 std::string interfaceName;
883 boost::container::flat_map<std::string,
884 std::variant<std::string>>
885 propertiesChanged;
886 std::string policy;
887 try
888 {
889 msg.read(interfaceName, propertiesChanged);
890 policy = std::get<std::string>(
891 propertiesChanged.begin()->second);
892 }
893 catch (std::exception& e)
894 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800895 phosphor::logging::log<phosphor::logging::level::ERR>(
896 "Unable to read power restore policy value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700897 powerRestorePolicyMatch.reset();
898 return;
899 }
900 invokePowerRestorePolicy(policy);
901 powerRestorePolicyMatch.reset();
902 });
903
904 // Check if it's already on DBus
905 conn->async_method_call(
906 [](boost::system::error_code ec,
907 const std::variant<std::string>& policyProperty) {
908 if (ec)
909 {
910 return;
911 }
912 powerRestorePolicyMatch.reset();
913 const std::string* policy =
914 std::get_if<std::string>(&policyProperty);
915 if (policy == nullptr)
916 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800917 phosphor::logging::log<phosphor::logging::level::ERR>(
918 "Unable to read power restore policy value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700919 return;
920 }
921 invokePowerRestorePolicy(*policy);
922 },
923 "xyz.openbmc_project.Settings",
924 "/xyz/openbmc_project/control/host0/power_restore_policy",
925 "org.freedesktop.DBus.Properties", "Get",
926 "xyz.openbmc_project.Control.Power.RestorePolicy",
927 "PowerRestorePolicy");
928 });
929}
930
931static void powerRestorePolicyStart()
932{
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800933 phosphor::logging::log<phosphor::logging::level::INFO>(
934 "Power restore policy started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700935 powerRestorePolicyLog();
936
937 // Get the desired delay time
938 // In case PowerRestoreDelay is not available, set a match for it
939 static std::unique_ptr<sdbusplus::bus::match::match>
940 powerRestoreDelayMatch = std::make_unique<sdbusplus::bus::match::match>(
941 *conn,
942 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
943 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Control."
944 "Power.RestoreDelay'",
945 [](sdbusplus::message::message& msg) {
946 std::string interfaceName;
947 boost::container::flat_map<std::string, std::variant<uint16_t>>
948 propertiesChanged;
949 int delay = 0;
950 try
951 {
952 msg.read(interfaceName, propertiesChanged);
953 delay =
954 std::get<uint16_t>(propertiesChanged.begin()->second);
955 }
956 catch (std::exception& e)
957 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800958 phosphor::logging::log<phosphor::logging::level::ERR>(
959 "Unable to read power restore delay value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700960 powerRestoreDelayMatch.reset();
961 return;
962 }
963 powerRestorePolicyDelay(delay);
964 powerRestoreDelayMatch.reset();
965 });
966
967 // Check if it's already on DBus
968 conn->async_method_call(
969 [](boost::system::error_code ec,
970 const std::variant<uint16_t>& delayProperty) {
971 if (ec)
972 {
973 return;
974 }
975 powerRestoreDelayMatch.reset();
976 const uint16_t* delay = std::get_if<uint16_t>(&delayProperty);
977 if (delay == nullptr)
978 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -0800979 phosphor::logging::log<phosphor::logging::level::ERR>(
980 "Unable to read power restore delay value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700981 return;
982 }
983 powerRestorePolicyDelay(*delay);
984 },
985 "xyz.openbmc_project.Settings",
986 "/xyz/openbmc_project/control/power_restore_delay",
987 "org.freedesktop.DBus.Properties", "Get",
988 "xyz.openbmc_project.Control.Power.RestoreDelay", "PowerRestoreDelay");
989}
990
991static void powerRestorePolicyCheck()
992{
993 // In case ACBoot is not available, set a match for it
994 static std::unique_ptr<sdbusplus::bus::match::match> acBootMatch =
995 std::make_unique<sdbusplus::bus::match::match>(
996 *conn,
997 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
998 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Common."
999 "ACBoot'",
1000 [](sdbusplus::message::message& msg) {
1001 std::string interfaceName;
1002 boost::container::flat_map<std::string,
1003 std::variant<std::string>>
1004 propertiesChanged;
1005 std::string acBoot;
1006 try
1007 {
1008 msg.read(interfaceName, propertiesChanged);
1009 acBoot = std::get<std::string>(
1010 propertiesChanged.begin()->second);
1011 }
1012 catch (std::exception& e)
1013 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001014 phosphor::logging::log<phosphor::logging::level::ERR>(
1015 "Unable to read AC Boot status");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001016 acBootMatch.reset();
1017 return;
1018 }
1019 if (acBoot == "Unknown")
1020 {
1021 return;
1022 }
1023 if (acBoot == "True")
1024 {
1025 // Start the Power Restore policy
1026 powerRestorePolicyStart();
1027 }
1028 acBootMatch.reset();
1029 });
1030
1031 // Check if it's already on DBus
1032 conn->async_method_call(
1033 [](boost::system::error_code ec,
1034 const std::variant<std::string>& acBootProperty) {
1035 if (ec)
1036 {
1037 return;
1038 }
1039 const std::string* acBoot =
1040 std::get_if<std::string>(&acBootProperty);
1041 if (acBoot == nullptr)
1042 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001043 phosphor::logging::log<phosphor::logging::level::ERR>(
1044 "Unable to read AC Boot status");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001045 return;
1046 }
1047 if (*acBoot == "Unknown")
1048 {
1049 return;
1050 }
1051 if (*acBoot == "True")
1052 {
1053 // Start the Power Restore policy
1054 powerRestorePolicyStart();
1055 }
1056 acBootMatch.reset();
1057 },
1058 "xyz.openbmc_project.Settings",
1059 "/xyz/openbmc_project/control/host0/ac_boot",
1060 "org.freedesktop.DBus.Properties", "Get",
1061 "xyz.openbmc_project.Common.ACBoot", "ACBoot");
1062}
1063
1064static bool requestGPIOEvents(
1065 const std::string& name, const std::function<void()>& handler,
1066 gpiod::line& gpioLine,
1067 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
1068{
1069 // Find the GPIO line
1070 gpioLine = gpiod::find_line(name);
1071 if (!gpioLine)
1072 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001073 std::string errMsg = "Failed to find the " + name + " line";
1074 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001075 return false;
1076 }
1077
1078 try
1079 {
1080 gpioLine.request(
1081 {"power-control", gpiod::line_request::EVENT_BOTH_EDGES});
1082 }
1083 catch (std::exception&)
1084 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001085 std::string errMsg = "Failed to request events for " + name;
1086 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001087 return false;
1088 }
1089
1090 int gpioLineFd = gpioLine.event_get_fd();
1091 if (gpioLineFd < 0)
1092 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001093 std::string errMsg = "Failed to name " + name + " fd";
1094 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001095 return false;
1096 }
1097
1098 gpioEventDescriptor.assign(gpioLineFd);
1099
1100 gpioEventDescriptor.async_wait(
1101 boost::asio::posix::stream_descriptor::wait_read,
1102 [&name, handler](const boost::system::error_code ec) {
1103 if (ec)
1104 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001105 std::string errMsg =
1106 name + " fd handler error: " + ec.message();
1107 phosphor::logging::log<phosphor::logging::level::ERR>(
1108 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001109 // TODO: throw here to force power-control to restart?
1110 return;
1111 }
1112 handler();
1113 });
1114 return true;
1115}
1116
1117static bool setGPIOOutput(const std::string& name, const int value,
1118 gpiod::line& gpioLine)
1119{
1120 // Find the GPIO line
1121 gpioLine = gpiod::find_line(name);
1122 if (!gpioLine)
1123 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001124 std::string errMsg = "Failed to find the " + name + " line";
1125 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001126 return false;
1127 }
1128
1129 // Request GPIO output to specified value
1130 try
1131 {
1132 gpioLine.request({__FUNCTION__, gpiod::line_request::DIRECTION_OUTPUT},
1133 value);
1134 }
1135 catch (std::exception&)
1136 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001137 std::string errMsg = "Failed to request " + name + " output";
1138 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001139 return false;
1140 }
1141
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001142 std::string logMsg = name + " set to " + std::to_string(value);
1143 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001144 return true;
1145}
1146
1147static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1148 const std::string& name, const int value,
1149 const int durationMs)
1150{
1151 // Set the masked GPIO line to the specified value
1152 maskedGPIOLine.set_value(value);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001153 std::string logMsg = name + " set to " + std::to_string(value);
1154 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001155 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001156 gpioAssertTimer.async_wait([maskedGPIOLine, value,
1157 name](const boost::system::error_code ec) {
1158 // Set the masked GPIO line back to the opposite value
1159 maskedGPIOLine.set_value(!value);
1160 std::string logMsg = name + " released";
1161 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
1162 if (ec)
1163 {
1164 // operation_aborted is expected if timer is canceled before
1165 // completion.
1166 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001167 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001168 std::string errMsg =
1169 name + " async_wait failed: " + ec.message();
1170 phosphor::logging::log<phosphor::logging::level::ERR>(
1171 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001172 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001173 }
1174 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001175 return 0;
1176}
1177
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001178static int setGPIOOutputForMs(const ConfigData& config, const int value,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001179 const int durationMs)
1180{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001181 int polarizedvalue;
1182 if (!config.polarity)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001183 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001184 polarizedvalue = value;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001185 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001186 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001187 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001188 polarizedvalue = !value;
1189 }
1190 // If the requested GPIO is masked, use the mask line to set the output
1191 if (powerButtonMask && config.lineName == powerOutConfig.lineName)
1192 {
1193 return setMaskedGPIOOutputForMs(powerButtonMask, config.lineName,
1194 polarizedvalue, durationMs);
1195 }
1196 if (resetButtonMask && config.lineName == resetOutConfig.lineName)
1197 {
1198 return setMaskedGPIOOutputForMs(resetButtonMask, config.lineName,
1199 polarizedvalue, durationMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001200 }
1201
1202 // No mask set, so request and set the GPIO normally
1203 gpiod::line gpioLine;
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001204 if (!setGPIOOutput(config.lineName, polarizedvalue, gpioLine))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001205 {
1206 return -1;
1207 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001208 const std::string name = config.lineName;
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001209
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001210 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001211 gpioAssertTimer.async_wait([gpioLine, polarizedvalue,
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001212 name](const boost::system::error_code ec) {
1213 // Set the GPIO line back to the opposite value
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001214 gpioLine.set_value(!polarizedvalue);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001215 std::string logMsg = name + " released";
1216 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
1217 if (ec)
1218 {
1219 // operation_aborted is expected if timer is canceled before
1220 // completion.
1221 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001222 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001223 std::string errMsg =
1224 name + " async_wait failed: " + ec.message();
1225 phosphor::logging::log<phosphor::logging::level::ERR>(
1226 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001227 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001228 }
1229 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001230 return 0;
1231}
1232
1233static void powerOn()
1234{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001235 setGPIOOutputForMs(powerOutConfig, 0, TimerMap["powerPulseTimeMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001236}
Naveen Moses117c34e2021-05-26 20:10:51 +05301237#ifdef CHASSIS_SYSTEM_RESET
1238static int slotPowerOn()
1239{
1240 if (power_control::slotPowerState != power_control::SlotPowerState::on)
1241 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001242
Naveen Moses117c34e2021-05-26 20:10:51 +05301243 slotPowerLine.set_value(1);
1244
1245 if (slotPowerLine.get_value() > 0)
1246 {
1247 setSlotPowerState(SlotPowerState::on);
1248 phosphor::logging::log<phosphor::logging::level::INFO>(
1249 "Slot Power is switched On\n");
1250 }
1251 else
1252 {
1253 return -1;
1254 }
1255 }
1256 else
1257 {
1258 phosphor::logging::log<phosphor::logging::level::INFO>(
1259 "Slot Power is already in 'On' state\n");
1260 return -1;
1261 }
1262 return 0;
1263}
1264static int slotPowerOff()
1265{
1266 if (power_control::slotPowerState != power_control::SlotPowerState::off)
1267 {
1268 slotPowerLine.set_value(0);
1269
1270 if (!(slotPowerLine.get_value() > 0))
1271 {
1272 setSlotPowerState(SlotPowerState::off);
1273 setPowerState(PowerState::off);
1274 phosphor::logging::log<phosphor::logging::level::INFO>(
1275 "Slot Power is switched Off\n");
1276 }
1277 else
1278 {
1279 return -1;
1280 }
1281 }
1282 else
1283 {
1284 phosphor::logging::log<phosphor::logging::level::INFO>(
1285 "Slot Power is already in 'Off' state\n");
1286 return -1;
1287 }
1288 return 0;
1289}
1290static void slotPowerCycle()
1291{
1292 phosphor::logging::log<phosphor::logging::level::INFO>(
1293 "Slot Power Cycle started\n");
1294 slotPowerOff();
1295 slotPowerCycleTimer.expires_after(
1296 std::chrono::milliseconds(TimerMap["slotPowerCycleTimeMs"]));
1297 slotPowerCycleTimer.async_wait([](const boost::system::error_code ec) {
1298 if (ec)
1299 {
1300 if (ec != boost::asio::error::operation_aborted)
1301 {
1302 std::string errMsg =
1303 "Slot Power cycle timer async_wait failed: " + ec.message();
1304 phosphor::logging::log<phosphor::logging::level::ERR>(
1305 errMsg.c_str());
1306 }
1307 phosphor::logging::log<phosphor::logging::level::INFO>(
1308 "Slot Power cycle timer canceled\n");
1309 return;
1310 }
1311 phosphor::logging::log<phosphor::logging::level::INFO>(
1312 "Slot Power cycle timer completed\n");
1313 slotPowerOn();
1314 phosphor::logging::log<phosphor::logging::level::INFO>(
1315 "Slot Power Cycle Completed\n");
1316 });
1317}
1318#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001319static void gracefulPowerOff()
1320{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001321 setGPIOOutputForMs(powerOutConfig, 0, TimerMap["powerPulseTimeMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001322}
1323
1324static void forcePowerOff()
1325{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001326 if (setGPIOOutputForMs(powerOutConfig, 0, TimerMap["forceOffPulseTimeMs"]) <
1327 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001328 {
1329 return;
1330 }
1331
1332 // If the force off timer expires, then the PCH power-button override
1333 // failed, so attempt the Unconditional Powerdown SMBus command.
1334 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1335 if (ec)
1336 {
1337 // operation_aborted is expected if timer is canceled before
1338 // completion.
1339 if (ec != boost::asio::error::operation_aborted)
1340 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001341 std::string errMsg =
1342 "Force power off async_wait failed: " + ec.message();
1343 phosphor::logging::log<phosphor::logging::level::ERR>(
1344 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001345 }
1346 return;
1347 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001348
1349 phosphor::logging::log<phosphor::logging::level::INFO>(
1350 "PCH Power-button override failed. Issuing Unconditional Powerdown "
1351 "SMBus command.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001352 const static constexpr size_t pchDevBusAddress = 3;
1353 const static constexpr size_t pchDevSlaveAddress = 0x44;
1354 const static constexpr size_t pchCmdReg = 0;
1355 const static constexpr size_t pchPowerDownCmd = 0x02;
1356 if (i2cSet(pchDevBusAddress, pchDevSlaveAddress, pchCmdReg,
1357 pchPowerDownCmd) < 0)
1358 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001359 phosphor::logging::log<phosphor::logging::level::ERR>(
1360 "Unconditional Powerdown command failed! Not sure what to do "
1361 "now.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001362 }
1363 });
1364}
1365
1366static void reset()
1367{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001368 setGPIOOutputForMs(resetOutConfig, 0, TimerMap["resetPulseTimeMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001369}
1370
1371static void gracefulPowerOffTimerStart()
1372{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001373 phosphor::logging::log<phosphor::logging::level::INFO>(
1374 "Graceful power-off timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001375 gracefulPowerOffTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301376 std::chrono::seconds(TimerMap["gracefulPowerOffTimeS"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001377 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1378 if (ec)
1379 {
1380 // operation_aborted is expected if timer is canceled before
1381 // completion.
1382 if (ec != boost::asio::error::operation_aborted)
1383 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001384 std::string errMsg =
1385 "Graceful power-off async_wait failed: " + ec.message();
1386 phosphor::logging::log<phosphor::logging::level::ERR>(
1387 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001388 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001389 phosphor::logging::log<phosphor::logging::level::INFO>(
1390 "Graceful power-off timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001391 return;
1392 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001393 phosphor::logging::log<phosphor::logging::level::INFO>(
1394 "Graceful power-off timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001395 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1396 });
1397}
1398
1399static void powerCycleTimerStart()
1400{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001401 phosphor::logging::log<phosphor::logging::level::INFO>(
1402 "Power-cycle timer started");
Priyatharshan P70120512020-09-16 18:47:20 +05301403 powerCycleTimer.expires_after(
1404 std::chrono::milliseconds(TimerMap["powerCycleTimeMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001405 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1406 if (ec)
1407 {
1408 // operation_aborted is expected if timer is canceled before
1409 // completion.
1410 if (ec != boost::asio::error::operation_aborted)
1411 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001412 std::string errMsg =
1413 "Power-cycle async_wait failed: " + ec.message();
1414 phosphor::logging::log<phosphor::logging::level::ERR>(
1415 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001416 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001417 phosphor::logging::log<phosphor::logging::level::INFO>(
1418 "Power-cycle timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001419 return;
1420 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001421 phosphor::logging::log<phosphor::logging::level::INFO>(
1422 "Power-cycle timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001423 sendPowerControlEvent(Event::powerCycleTimerExpired);
1424 });
1425}
1426
1427static void psPowerOKWatchdogTimerStart()
1428{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001429 phosphor::logging::log<phosphor::logging::level::INFO>(
1430 "power supply power OK watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001431 psPowerOKWatchdogTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301432 std::chrono::milliseconds(TimerMap["psPowerOKWatchdogTimeMs"]));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001433 psPowerOKWatchdogTimer.async_wait([](const boost::system::error_code ec) {
1434 if (ec)
1435 {
1436 // operation_aborted is expected if timer is canceled before
1437 // completion.
1438 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001439 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001440 std::string errMsg =
1441 "power supply power OK watchdog async_wait failed: " +
1442 ec.message();
1443 phosphor::logging::log<phosphor::logging::level::ERR>(
1444 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001445 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001446 phosphor::logging::log<phosphor::logging::level::INFO>(
1447 "power supply power OK watchdog timer canceled");
1448 return;
1449 }
1450 phosphor::logging::log<phosphor::logging::level::INFO>(
1451 "power supply power OK watchdog timer expired");
1452 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1453 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001454}
1455
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001456static void warmResetCheckTimerStart()
1457{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001458 phosphor::logging::log<phosphor::logging::level::INFO>(
1459 "Warm reset check timer started");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001460 warmResetCheckTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301461 std::chrono::milliseconds(TimerMap["warmResetCheckTimeMs"]));
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001462 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1463 if (ec)
1464 {
1465 // operation_aborted is expected if timer is canceled before
1466 // completion.
1467 if (ec != boost::asio::error::operation_aborted)
1468 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001469 std::string errMsg =
1470 "Warm reset check async_wait failed: " + ec.message();
1471 phosphor::logging::log<phosphor::logging::level::ERR>(
1472 errMsg.c_str());
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001473 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001474 phosphor::logging::log<phosphor::logging::level::INFO>(
1475 "Warm reset check timer canceled");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001476 return;
1477 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001478 phosphor::logging::log<phosphor::logging::level::INFO>(
1479 "Warm reset check timer completed");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001480 sendPowerControlEvent(Event::warmResetDetected);
1481 });
1482}
1483
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001484static void pohCounterTimerStart()
1485{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001486 phosphor::logging::log<phosphor::logging::level::INFO>("POH timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001487 // Set the time-out as 1 hour, to align with POH command in ipmid
1488 pohCounterTimer.expires_after(std::chrono::hours(1));
1489 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1490 if (ec)
1491 {
1492 // operation_aborted is expected if timer is canceled before
1493 // completion.
1494 if (ec != boost::asio::error::operation_aborted)
1495 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001496 std::string errMsg =
1497 "POH timer async_wait failed: " + ec.message();
1498 phosphor::logging::log<phosphor::logging::level::ERR>(
1499 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001500 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001501 phosphor::logging::log<phosphor::logging::level::INFO>(
1502 "POH timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001503 return;
1504 }
1505
1506 if (getHostState(powerState) !=
1507 "xyz.openbmc_project.State.Host.HostState.Running")
1508 {
1509 return;
1510 }
1511
1512 conn->async_method_call(
1513 [](boost::system::error_code ec,
1514 const std::variant<uint32_t>& pohCounterProperty) {
1515 if (ec)
1516 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001517 phosphor::logging::log<phosphor::logging::level::INFO>(
1518 "error to get poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001519 return;
1520 }
1521 const uint32_t* pohCounter =
1522 std::get_if<uint32_t>(&pohCounterProperty);
1523 if (pohCounter == nullptr)
1524 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001525 phosphor::logging::log<phosphor::logging::level::INFO>(
1526 "unable to read poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001527 return;
1528 }
1529
1530 conn->async_method_call(
1531 [](boost::system::error_code ec) {
1532 if (ec)
1533 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001534 phosphor::logging::log<
1535 phosphor::logging::level::INFO>(
1536 "failed to set poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001537 }
1538 },
1539 "xyz.openbmc_project.Settings",
1540 "/xyz/openbmc_project/state/chassis0",
1541 "org.freedesktop.DBus.Properties", "Set",
1542 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1543 std::variant<uint32_t>(*pohCounter + 1));
1544 },
1545 "xyz.openbmc_project.Settings",
1546 "/xyz/openbmc_project/state/chassis0",
1547 "org.freedesktop.DBus.Properties", "Get",
1548 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1549
1550 pohCounterTimerStart();
1551 });
1552}
1553
1554static void currentHostStateMonitor()
1555{
Yong Li8d660212019-12-27 10:18:10 +08001556 if (getHostState(powerState) ==
1557 "xyz.openbmc_project.State.Host.HostState.Running")
1558 {
1559 pohCounterTimerStart();
1560 // Clear the restart cause set for the next restart
1561 clearRestartCause();
1562 }
1563 else
1564 {
1565 pohCounterTimer.cancel();
1566 // Set the restart cause set for this restart
1567 setRestartCause();
1568 }
1569
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001570 static auto match = sdbusplus::bus::match::match(
1571 *conn,
1572 "type='signal',member='PropertiesChanged', "
1573 "interface='org.freedesktop.DBus.Properties', "
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001574 "arg0='xyz.openbmc_project.State.Host'",
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001575 [](sdbusplus::message::message& message) {
1576 std::string intfName;
1577 std::map<std::string, std::variant<std::string>> properties;
1578
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001579 try
1580 {
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001581 message.read(intfName, properties);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001582 }
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001583 catch (std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001584 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001585 phosphor::logging::log<phosphor::logging::level::ERR>(
1586 "Unable to read host state");
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001587 return;
1588 }
1589 if (properties.empty())
1590 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001591 phosphor::logging::log<phosphor::logging::level::ERR>(
1592 "ERROR: Empty PropertiesChanged signal received");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001593 return;
1594 }
1595
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001596 // We only want to check for CurrentHostState
1597 if (properties.begin()->first != "CurrentHostState")
1598 {
1599 return;
1600 }
1601 std::string* currentHostState =
1602 std::get_if<std::string>(&(properties.begin()->second));
1603 if (currentHostState == nullptr)
1604 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001605 std::string errMsg =
1606 properties.begin()->first + " property invalid";
1607 phosphor::logging::log<phosphor::logging::level::ERR>(
1608 errMsg.c_str());
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001609 return;
1610 }
1611
1612 if (*currentHostState ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001613 "xyz.openbmc_project.State.Host.HostState.Running")
1614 {
1615 pohCounterTimerStart();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001616 // Clear the restart cause set for the next restart
1617 clearRestartCause();
Yong Li8d660212019-12-27 10:18:10 +08001618 sd_journal_send("MESSAGE=Host system DC power is on",
1619 "PRIORITY=%i", LOG_INFO,
1620 "REDFISH_MESSAGE_ID=%s",
1621 "OpenBMC.0.1.DCPowerOn", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001622 }
1623 else
1624 {
1625 pohCounterTimer.cancel();
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301626 // POST_COMPLETE GPIO event is not working in some platforms
1627 // when power state is changed to OFF. This resulted in
1628 // 'OperatingSystemState' to stay at 'Standby', even though
1629 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1630 // if HostState is trurned to OFF.
1631 osIface->set_property("OperatingSystemState",
1632 std::string("Inactive"));
1633
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001634 // Set the restart cause set for this restart
1635 setRestartCause();
Rashmi RV89f61312020-01-22 15:41:50 +05301636 resetACBootProperty();
Yong Li8d660212019-12-27 10:18:10 +08001637 sd_journal_send("MESSAGE=Host system DC power is off",
1638 "PRIORITY=%i", LOG_INFO,
1639 "REDFISH_MESSAGE_ID=%s",
1640 "OpenBMC.0.1.DCPowerOff", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001641 }
1642 });
1643}
1644
1645static void sioPowerGoodWatchdogTimerStart()
1646{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001647 phosphor::logging::log<phosphor::logging::level::INFO>(
1648 "SIO power good watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001649 sioPowerGoodWatchdogTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301650 std::chrono::milliseconds(TimerMap["sioPowerGoodWatchdogTimeMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001651 sioPowerGoodWatchdogTimer.async_wait(
1652 [](const boost::system::error_code ec) {
1653 if (ec)
1654 {
1655 // operation_aborted is expected if timer is canceled before
1656 // completion.
1657 if (ec != boost::asio::error::operation_aborted)
1658 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001659 std::string errMsg =
1660 "SIO power good watchdog async_wait failed: " +
1661 ec.message();
1662 phosphor::logging::log<phosphor::logging::level::ERR>(
1663 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001664 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001665 phosphor::logging::log<phosphor::logging::level::INFO>(
1666 "SIO power good watchdog timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001667 return;
1668 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001669 phosphor::logging::log<phosphor::logging::level::INFO>(
1670 "SIO power good watchdog timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001671 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1672 });
1673}
1674
1675static void powerStateOn(const Event event)
1676{
1677 logEvent(__FUNCTION__, event);
1678 switch (event)
1679 {
1680 case Event::psPowerOKDeAssert:
1681 setPowerState(PowerState::off);
1682 // DC power is unexpectedly lost, beep
1683 beep(beepPowerFail);
1684 break;
1685 case Event::sioS5Assert:
1686 setPowerState(PowerState::transitionToOff);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001687 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001688 break;
Jason M. Billsfb957332021-01-28 13:18:46 -08001689#if USE_PLT_RST
1690 case Event::pltRstAssert:
1691#else
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001692 case Event::postCompleteDeAssert:
Jason M. Billsfb957332021-01-28 13:18:46 -08001693#endif
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001694 setPowerState(PowerState::checkForWarmReset);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001695 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001696 warmResetCheckTimerStart();
1697 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001698 case Event::powerButtonPressed:
1699 setPowerState(PowerState::gracefulTransitionToOff);
1700 gracefulPowerOffTimerStart();
1701 break;
1702 case Event::powerOffRequest:
1703 setPowerState(PowerState::transitionToOff);
1704 forcePowerOff();
1705 break;
1706 case Event::gracefulPowerOffRequest:
1707 setPowerState(PowerState::gracefulTransitionToOff);
1708 gracefulPowerOffTimerStart();
1709 gracefulPowerOff();
1710 break;
1711 case Event::powerCycleRequest:
1712 setPowerState(PowerState::transitionToCycleOff);
1713 forcePowerOff();
1714 break;
1715 case Event::gracefulPowerCycleRequest:
1716 setPowerState(PowerState::gracefulTransitionToCycleOff);
1717 gracefulPowerOffTimerStart();
1718 gracefulPowerOff();
1719 break;
1720 case Event::resetRequest:
1721 reset();
1722 break;
1723 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001724 phosphor::logging::log<phosphor::logging::level::INFO>(
1725 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001726 break;
1727 }
1728}
1729
1730static void powerStateWaitForPSPowerOK(const Event event)
1731{
1732 logEvent(__FUNCTION__, event);
1733 switch (event)
1734 {
1735 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301736 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001737 // Cancel any GPIO assertions held during the transition
1738 gpioAssertTimer.cancel();
1739 psPowerOKWatchdogTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301740 if (sioEnabled == true)
1741 {
1742 sioPowerGoodWatchdogTimerStart();
1743 setPowerState(PowerState::waitForSIOPowerGood);
1744 }
1745 else
1746 {
1747 setPowerState(PowerState::on);
1748 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001749 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301750 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001751 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001752 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001753 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001754 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001755 case Event::sioPowerGoodAssert:
1756 psPowerOKWatchdogTimer.cancel();
1757 setPowerState(PowerState::on);
1758 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001759 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001760 phosphor::logging::log<phosphor::logging::level::INFO>(
1761 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001762 break;
1763 }
1764}
1765
1766static void powerStateWaitForSIOPowerGood(const Event event)
1767{
1768 logEvent(__FUNCTION__, event);
1769 switch (event)
1770 {
1771 case Event::sioPowerGoodAssert:
1772 sioPowerGoodWatchdogTimer.cancel();
1773 setPowerState(PowerState::on);
1774 break;
1775 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001776 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001777 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001778 break;
1779 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001780 phosphor::logging::log<phosphor::logging::level::INFO>(
1781 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001782 break;
1783 }
1784}
1785
1786static void powerStateOff(const Event event)
1787{
1788 logEvent(__FUNCTION__, event);
1789 switch (event)
1790 {
1791 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301792 {
1793 if (sioEnabled == true)
1794 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001795 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301796 setPowerState(PowerState::waitForSIOPowerGood);
1797 }
1798 else
1799 {
1800 setPowerState(PowerState::on);
1801 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001802 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301803 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001804 case Event::sioS5DeAssert:
1805 setPowerState(PowerState::waitForPSPowerOK);
1806 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001807 case Event::sioPowerGoodAssert:
1808 setPowerState(PowerState::on);
1809 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001810 case Event::powerButtonPressed:
1811 psPowerOKWatchdogTimerStart();
1812 setPowerState(PowerState::waitForPSPowerOK);
1813 break;
1814 case Event::powerOnRequest:
1815 psPowerOKWatchdogTimerStart();
1816 setPowerState(PowerState::waitForPSPowerOK);
1817 powerOn();
1818 break;
1819 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001820 phosphor::logging::log<phosphor::logging::level::INFO>(
1821 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001822 break;
1823 }
1824}
1825
1826static void powerStateTransitionToOff(const Event event)
1827{
1828 logEvent(__FUNCTION__, event);
1829 switch (event)
1830 {
1831 case Event::psPowerOKDeAssert:
1832 // Cancel any GPIO assertions held during the transition
1833 gpioAssertTimer.cancel();
1834 setPowerState(PowerState::off);
1835 break;
1836 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001837 phosphor::logging::log<phosphor::logging::level::INFO>(
1838 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001839 break;
1840 }
1841}
1842
1843static void powerStateGracefulTransitionToOff(const Event event)
1844{
1845 logEvent(__FUNCTION__, event);
1846 switch (event)
1847 {
1848 case Event::psPowerOKDeAssert:
1849 gracefulPowerOffTimer.cancel();
1850 setPowerState(PowerState::off);
1851 break;
1852 case Event::gracefulPowerOffTimerExpired:
1853 setPowerState(PowerState::on);
1854 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001855 case Event::powerOffRequest:
1856 gracefulPowerOffTimer.cancel();
1857 setPowerState(PowerState::transitionToOff);
1858 forcePowerOff();
1859 break;
1860 case Event::powerCycleRequest:
1861 gracefulPowerOffTimer.cancel();
1862 setPowerState(PowerState::transitionToCycleOff);
1863 forcePowerOff();
1864 break;
1865 case Event::resetRequest:
1866 gracefulPowerOffTimer.cancel();
1867 setPowerState(PowerState::on);
1868 reset();
1869 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001870 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001871 phosphor::logging::log<phosphor::logging::level::INFO>(
1872 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001873 break;
1874 }
1875}
1876
1877static void powerStateCycleOff(const Event event)
1878{
1879 logEvent(__FUNCTION__, event);
1880 switch (event)
1881 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001882 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301883 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001884 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301885 if (sioEnabled == true)
1886 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001887 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301888 setPowerState(PowerState::waitForSIOPowerGood);
1889 }
1890 else
1891 {
1892 setPowerState(PowerState::on);
1893 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001894 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301895 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001896 case Event::sioS5DeAssert:
1897 powerCycleTimer.cancel();
1898 setPowerState(PowerState::waitForPSPowerOK);
1899 break;
1900 case Event::powerButtonPressed:
1901 powerCycleTimer.cancel();
1902 psPowerOKWatchdogTimerStart();
1903 setPowerState(PowerState::waitForPSPowerOK);
1904 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001905 case Event::powerCycleTimerExpired:
1906 psPowerOKWatchdogTimerStart();
1907 setPowerState(PowerState::waitForPSPowerOK);
1908 powerOn();
1909 break;
1910 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001911 phosphor::logging::log<phosphor::logging::level::INFO>(
1912 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001913 break;
1914 }
1915}
1916
1917static void powerStateTransitionToCycleOff(const Event event)
1918{
1919 logEvent(__FUNCTION__, event);
1920 switch (event)
1921 {
1922 case Event::psPowerOKDeAssert:
1923 // Cancel any GPIO assertions held during the transition
1924 gpioAssertTimer.cancel();
1925 setPowerState(PowerState::cycleOff);
1926 powerCycleTimerStart();
1927 break;
1928 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001929 phosphor::logging::log<phosphor::logging::level::INFO>(
1930 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001931 break;
1932 }
1933}
1934
1935static void powerStateGracefulTransitionToCycleOff(const Event event)
1936{
1937 logEvent(__FUNCTION__, event);
1938 switch (event)
1939 {
1940 case Event::psPowerOKDeAssert:
1941 gracefulPowerOffTimer.cancel();
1942 setPowerState(PowerState::cycleOff);
1943 powerCycleTimerStart();
1944 break;
1945 case Event::gracefulPowerOffTimerExpired:
1946 setPowerState(PowerState::on);
1947 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001948 case Event::powerOffRequest:
1949 gracefulPowerOffTimer.cancel();
1950 setPowerState(PowerState::transitionToOff);
1951 forcePowerOff();
1952 break;
1953 case Event::powerCycleRequest:
1954 gracefulPowerOffTimer.cancel();
1955 setPowerState(PowerState::transitionToCycleOff);
1956 forcePowerOff();
1957 break;
1958 case Event::resetRequest:
1959 gracefulPowerOffTimer.cancel();
1960 setPowerState(PowerState::on);
1961 reset();
1962 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001963 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001964 phosphor::logging::log<phosphor::logging::level::INFO>(
1965 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001966 break;
1967 }
1968}
1969
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001970static void powerStateCheckForWarmReset(const Event event)
1971{
1972 logEvent(__FUNCTION__, event);
1973 switch (event)
1974 {
1975 case Event::sioS5Assert:
1976 warmResetCheckTimer.cancel();
1977 setPowerState(PowerState::transitionToOff);
1978 break;
1979 case Event::warmResetDetected:
1980 setPowerState(PowerState::on);
1981 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001982 case Event::psPowerOKDeAssert:
1983 warmResetCheckTimer.cancel();
1984 setPowerState(PowerState::off);
1985 // DC power is unexpectedly lost, beep
1986 beep(beepPowerFail);
1987 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001988 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001989 phosphor::logging::log<phosphor::logging::level::INFO>(
1990 "No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001991 break;
1992 }
1993}
1994
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001995static void psPowerOKHandler()
1996{
1997 gpiod::line_event gpioLineEvent = psPowerOKLine.event_read();
1998
1999 Event powerControlEvent =
2000 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
2001 ? Event::psPowerOKAssert
2002 : Event::psPowerOKDeAssert;
2003
2004 sendPowerControlEvent(powerControlEvent);
2005 psPowerOKEvent.async_wait(
2006 boost::asio::posix::stream_descriptor::wait_read,
2007 [](const boost::system::error_code ec) {
2008 if (ec)
2009 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002010 std::string errMsg =
2011 "power supply power OK handler error: " + ec.message();
2012 phosphor::logging::log<phosphor::logging::level::ERR>(
2013 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002014 return;
2015 }
2016 psPowerOKHandler();
2017 });
2018}
2019
2020static void sioPowerGoodHandler()
2021{
2022 gpiod::line_event gpioLineEvent = sioPowerGoodLine.event_read();
2023
2024 Event powerControlEvent =
2025 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE
2026 ? Event::sioPowerGoodAssert
2027 : Event::sioPowerGoodDeAssert;
2028
2029 sendPowerControlEvent(powerControlEvent);
2030 sioPowerGoodEvent.async_wait(
2031 boost::asio::posix::stream_descriptor::wait_read,
2032 [](const boost::system::error_code ec) {
2033 if (ec)
2034 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002035 std::string errMsg =
2036 "SIO power good handler error: " + ec.message();
2037 phosphor::logging::log<phosphor::logging::level::ERR>(
2038 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002039 return;
2040 }
2041 sioPowerGoodHandler();
2042 });
2043}
2044
2045static void sioOnControlHandler()
2046{
2047 gpiod::line_event gpioLineEvent = sioOnControlLine.event_read();
2048
2049 bool sioOnControl =
2050 gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE;
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002051 std::string logMsg =
2052 "SIO_ONCONTROL value changed: " + std::to_string(sioOnControl);
2053 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002054 sioOnControlEvent.async_wait(
2055 boost::asio::posix::stream_descriptor::wait_read,
2056 [](const boost::system::error_code ec) {
2057 if (ec)
2058 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002059 std::string errMsg =
2060 "SIO ONCONTROL handler error: " + ec.message();
2061 phosphor::logging::log<phosphor::logging::level::ERR>(
2062 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002063 return;
2064 }
2065 sioOnControlHandler();
2066 });
2067}
2068
2069static void sioS5Handler()
2070{
2071 gpiod::line_event gpioLineEvent = sioS5Line.event_read();
2072
2073 Event powerControlEvent =
2074 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE
2075 ? Event::sioS5Assert
2076 : Event::sioS5DeAssert;
2077
2078 sendPowerControlEvent(powerControlEvent);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002079 sioS5Event.async_wait(
2080 boost::asio::posix::stream_descriptor::wait_read,
2081 [](const boost::system::error_code ec) {
2082 if (ec)
2083 {
2084 std::string errMsg = "SIO S5 handler error: " + ec.message();
2085 phosphor::logging::log<phosphor::logging::level::ERR>(
2086 errMsg.c_str());
2087 return;
2088 }
2089 sioS5Handler();
2090 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002091}
2092
2093static void powerButtonHandler()
2094{
2095 gpiod::line_event gpioLineEvent = powerButtonLine.event_read();
2096
2097 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2098 {
2099 powerButtonPressLog();
2100 powerButtonIface->set_property("ButtonPressed", true);
2101 if (!powerButtonMask)
2102 {
2103 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002104 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002105 }
2106 else
2107 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002108 phosphor::logging::log<phosphor::logging::level::INFO>(
2109 "power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002110 }
2111 }
2112 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2113 {
2114 powerButtonIface->set_property("ButtonPressed", false);
2115 }
2116 powerButtonEvent.async_wait(
2117 boost::asio::posix::stream_descriptor::wait_read,
2118 [](const boost::system::error_code ec) {
2119 if (ec)
2120 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002121 std::string errMsg =
2122 "power button handler error: " + ec.message();
2123 phosphor::logging::log<phosphor::logging::level::ERR>(
2124 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002125 return;
2126 }
2127 powerButtonHandler();
2128 });
2129}
2130
2131static void resetButtonHandler()
2132{
2133 gpiod::line_event gpioLineEvent = resetButtonLine.event_read();
2134
2135 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2136 {
2137 resetButtonPressLog();
2138 resetButtonIface->set_property("ButtonPressed", true);
2139 if (!resetButtonMask)
2140 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002141 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002142 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002143 }
2144 else
2145 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002146 phosphor::logging::log<phosphor::logging::level::INFO>(
2147 "reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002148 }
2149 }
2150 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2151 {
2152 resetButtonIface->set_property("ButtonPressed", false);
2153 }
2154 resetButtonEvent.async_wait(
2155 boost::asio::posix::stream_descriptor::wait_read,
2156 [](const boost::system::error_code ec) {
2157 if (ec)
2158 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002159 std::string errMsg =
2160 "reset button handler error: " + ec.message();
2161 phosphor::logging::log<phosphor::logging::level::ERR>(
2162 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002163 return;
2164 }
2165 resetButtonHandler();
2166 });
2167}
2168
Vijay Khemka04175c22020-10-09 14:28:11 -07002169#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002170static constexpr auto systemdBusname = "org.freedesktop.systemd1";
2171static constexpr auto systemdPath = "/org/freedesktop/systemd1";
2172static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
2173static constexpr auto systemTargetName = "chassis-system-reset.target";
2174
2175void systemReset()
2176{
2177 conn->async_method_call(
2178 [](boost::system::error_code ec) {
2179 if (ec)
2180 {
2181 phosphor::logging::log<phosphor::logging::level::ERR>(
2182 "Failed to call chassis system reset",
2183 phosphor::logging::entry("ERR=%s", ec.message().c_str()));
2184 }
2185 },
2186 systemdBusname, systemdPath, systemdInterface, "StartUnit",
2187 systemTargetName, "replace");
2188}
Vijay Khemka04175c22020-10-09 14:28:11 -07002189#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002190
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002191static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002192{
2193 conn->async_method_call(
2194 [](boost::system::error_code ec) {
2195 if (ec)
2196 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002197 phosphor::logging::log<phosphor::logging::level::INFO>(
2198 "failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002199 }
2200 },
Chen Yugang303bd582019-11-01 08:45:06 +08002201 "xyz.openbmc_project.Settings",
2202 "/xyz/openbmc_project/Chassis/Control/NMISource",
2203 "org.freedesktop.DBus.Properties", "Set",
2204 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
2205 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002206}
2207
2208static void nmiReset(void)
2209{
2210 static constexpr const uint8_t value = 1;
2211 const static constexpr int nmiOutPulseTimeMs = 200;
2212
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002213 phosphor::logging::log<phosphor::logging::level::INFO>("NMI out action");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002214 nmiOutLine.set_value(value);
Priyatharshan P70120512020-09-16 18:47:20 +05302215 std::string logMsg =
2216 nmiOutConfig.lineName + " set to " + std::to_string(value);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002217 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002218 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2219 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2220 // restore the NMI_OUT GPIO line back to the opposite value
2221 nmiOutLine.set_value(!value);
Priyatharshan P70120512020-09-16 18:47:20 +05302222 std::string logMsg = nmiOutConfig.lineName + " released";
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002223 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002224 if (ec)
2225 {
2226 // operation_aborted is expected if timer is canceled before
2227 // completion.
2228 if (ec != boost::asio::error::operation_aborted)
2229 {
Priyatharshan P70120512020-09-16 18:47:20 +05302230 std::string errMsg = nmiOutConfig.lineName +
2231 " async_wait failed: " + ec.message();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002232 phosphor::logging::log<phosphor::logging::level::ERR>(
2233 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002234 }
2235 }
2236 });
2237 // log to redfish
2238 nmiDiagIntLog();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002239 phosphor::logging::log<phosphor::logging::level::INFO>(
2240 "NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002241 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002242 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002243}
2244
2245static void nmiSourcePropertyMonitor(void)
2246{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002247 phosphor::logging::log<phosphor::logging::level::INFO>(
2248 "NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002249
2250 static std::unique_ptr<sdbusplus::bus::match::match> nmiSourceMatch =
2251 std::make_unique<sdbusplus::bus::match::match>(
2252 *conn,
2253 "type='signal',interface='org.freedesktop.DBus.Properties',"
Chen Yugang303bd582019-11-01 08:45:06 +08002254 "member='PropertiesChanged',arg0namespace='xyz.openbmc_project."
2255 "Chassis.Control."
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002256 "NMISource'",
2257 [](sdbusplus::message::message& msg) {
2258 std::string interfaceName;
2259 boost::container::flat_map<std::string,
2260 std::variant<bool, std::string>>
2261 propertiesChanged;
2262 std::string state;
2263 bool value = true;
2264 try
2265 {
2266 msg.read(interfaceName, propertiesChanged);
2267 if (propertiesChanged.begin()->first == "Enabled")
2268 {
2269 value =
2270 std::get<bool>(propertiesChanged.begin()->second);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002271 std::string logMsg =
2272 " NMI Enabled propertiesChanged value: " +
2273 std::to_string(value);
2274 phosphor::logging::log<phosphor::logging::level::INFO>(
2275 logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002276 nmiEnabled = value;
2277 if (nmiEnabled)
2278 {
2279 nmiReset();
2280 }
2281 }
2282 }
2283 catch (std::exception& e)
2284 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002285 phosphor::logging::log<phosphor::logging::level::ERR>(
2286 "Unable to read NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002287 return;
2288 }
2289 });
2290}
2291
2292static void setNmiSource()
2293{
2294 conn->async_method_call(
2295 [](boost::system::error_code ec) {
2296 if (ec)
2297 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002298 phosphor::logging::log<phosphor::logging::level::ERR>(
2299 "failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002300 }
2301 },
Chen Yugang303bd582019-11-01 08:45:06 +08002302 "xyz.openbmc_project.Settings",
2303 "/xyz/openbmc_project/Chassis/Control/NMISource",
2304 "org.freedesktop.DBus.Properties", "Set",
2305 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
2306 std::variant<std::string>{"xyz.openbmc_project.Chassis.Control."
2307 "NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002308 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002309 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002310}
2311
2312static void nmiButtonHandler()
2313{
2314 gpiod::line_event gpioLineEvent = nmiButtonLine.event_read();
2315
2316 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2317 {
2318 nmiButtonPressLog();
2319 nmiButtonIface->set_property("ButtonPressed", true);
2320 if (nmiButtonMasked)
2321 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002322 phosphor::logging::log<phosphor::logging::level::INFO>(
2323 "NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002324 }
2325 else
2326 {
2327 setNmiSource();
2328 }
2329 }
2330 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2331 {
2332 nmiButtonIface->set_property("ButtonPressed", false);
2333 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002334 nmiButtonEvent.async_wait(
2335 boost::asio::posix::stream_descriptor::wait_read,
2336 [](const boost::system::error_code ec) {
2337 if (ec)
2338 {
2339 std::string errMsg =
2340 "NMI button handler error: " + ec.message();
2341 phosphor::logging::log<phosphor::logging::level::ERR>(
2342 errMsg.c_str());
2343 return;
2344 }
2345 nmiButtonHandler();
2346 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002347}
2348
2349static void idButtonHandler()
2350{
2351 gpiod::line_event gpioLineEvent = idButtonLine.event_read();
2352
2353 if (gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE)
2354 {
2355 idButtonIface->set_property("ButtonPressed", true);
2356 }
2357 else if (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE)
2358 {
2359 idButtonIface->set_property("ButtonPressed", false);
2360 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002361 idButtonEvent.async_wait(
2362 boost::asio::posix::stream_descriptor::wait_read,
2363 [](const boost::system::error_code& ec) {
2364 if (ec)
2365 {
2366 std::string errMsg = "ID button handler error: " + ec.message();
2367 phosphor::logging::log<phosphor::logging::level::ERR>(
2368 errMsg.c_str());
2369 return;
2370 }
2371 idButtonHandler();
2372 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002373}
2374
Jason M. Billsfb957332021-01-28 13:18:46 -08002375static void pltRstHandler(bool pltRst)
2376{
2377 if (pltRst)
2378 {
2379 sendPowerControlEvent(Event::pltRstDeAssert);
2380 }
2381 else
2382 {
2383 sendPowerControlEvent(Event::pltRstAssert);
2384 }
2385}
2386
2387static void hostMiscHandler(sdbusplus::message::message& msg)
2388{
2389 std::string interfaceName;
2390 boost::container::flat_map<std::string, std::variant<bool>>
2391 propertiesChanged;
2392 bool pltRst;
2393 try
2394 {
2395 msg.read(interfaceName, propertiesChanged);
2396 }
2397 catch (std::exception& e)
2398 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002399 phosphor::logging::log<phosphor::logging::level::ERR>(
2400 "Unable to read Host Misc status");
Jason M. Billsfb957332021-01-28 13:18:46 -08002401 return;
2402 }
2403 if (propertiesChanged.empty())
2404 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002405 phosphor::logging::log<phosphor::logging::level::ERR>(
2406 "ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002407 return;
2408 }
2409
2410 for (auto& [property, value] : propertiesChanged)
2411 {
2412 if (property == "ESpiPlatformReset")
2413 {
2414 bool* pltRst = std::get_if<bool>(&value);
2415 if (pltRst == nullptr)
2416 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002417 std::string errMsg = property + " property invalid";
2418 phosphor::logging::log<phosphor::logging::level::ERR>(
2419 errMsg.c_str());
Jason M. Billsfb957332021-01-28 13:18:46 -08002420 return;
2421 }
2422 pltRstHandler(*pltRst);
2423 }
2424 }
2425}
2426
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002427static void postCompleteHandler()
2428{
2429 gpiod::line_event gpioLineEvent = postCompleteLine.event_read();
2430
2431 bool postComplete =
2432 gpioLineEvent.event_type == gpiod::line_event::FALLING_EDGE;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002433 if (postComplete)
2434 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002435 sendPowerControlEvent(Event::postCompleteAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002436 osIface->set_property("OperatingSystemState", std::string("Standby"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002437 }
2438 else
2439 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002440 sendPowerControlEvent(Event::postCompleteDeAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002441 osIface->set_property("OperatingSystemState", std::string("Inactive"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002442 }
2443 postCompleteEvent.async_wait(
2444 boost::asio::posix::stream_descriptor::wait_read,
2445 [](const boost::system::error_code ec) {
2446 if (ec)
2447 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002448 std::string errMsg =
2449 "POST complete handler error: " + ec.message();
2450 phosphor::logging::log<phosphor::logging::level::ERR>(
2451 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002452 return;
2453 }
2454 postCompleteHandler();
2455 });
2456}
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302457
2458static int loadConfigValues()
2459{
2460 const std::string configFilePath =
2461 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2462 ".json";
2463 std::ifstream configFile(configFilePath.c_str());
2464 if (!configFile.is_open())
2465 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002466 phosphor::logging::log<phosphor::logging::level::ERR>(
2467 "loadConfigValues : Cannot open config path");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302468 return -1;
2469 }
Zev Weiss1aa08b22021-09-15 17:06:20 -05002470 auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302471
Priyatharshan P70120512020-09-16 18:47:20 +05302472 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302473 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002474 phosphor::logging::log<phosphor::logging::level::ERR>(
2475 "Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302476 return -1;
2477 }
Priyatharshan P70120512020-09-16 18:47:20 +05302478 auto gpios = jsonData["gpio_configs"];
2479 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302480
Priyatharshan P70120512020-09-16 18:47:20 +05302481 ConfigData* tempGpioData;
2482
2483 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302484 {
Priyatharshan P70120512020-09-16 18:47:20 +05302485 if (!gpioConfig.contains("Name"))
2486 {
2487 phosphor::logging::log<phosphor::logging::level::ERR>(
2488 "The 'Name' field must be defined in Json file");
2489 return -1;
2490 }
2491
2492 // Iterate through the powersignal map to check if the gpio json config
2493 // entry is valid
2494 std::string gpioName = gpioConfig["Name"];
2495 auto signalMapIter = powerSignalMap.find(gpioName);
2496 if (signalMapIter == powerSignalMap.end())
2497 {
2498 std::string errMsg = "Undefined Name : " + gpioName;
2499 phosphor::logging::log<phosphor::logging::level::ERR>(
2500 errMsg.c_str());
2501 return -1;
2502 }
2503
2504 // assign the power signal name to the corresponding structure reference
2505 // from map then fillup the structure with coressponding json config
2506 // value
2507 tempGpioData = signalMapIter->second;
2508 tempGpioData->name = gpioName;
2509
2510 if (!gpioConfig.contains("Type"))
2511 {
2512 phosphor::logging::log<phosphor::logging::level::ERR>(
2513 "The \'Type\' field must be defined in Json file");
2514 return -1;
2515 }
2516
2517 std::string signalType = gpioConfig["Type"];
2518 if (signalType == "GPIO")
2519 {
2520 tempGpioData->type = ConfigType::GPIO;
2521 }
2522 else if (signalType == "DBUS")
2523 {
2524 tempGpioData->type = ConfigType::DBUS;
2525 }
2526 else
2527 {
2528 std::string errMsg = "Undefined Type : " + signalType;
2529 phosphor::logging::log<phosphor::logging::level::ERR>(
2530 errMsg.c_str());
2531 return -1;
2532 }
2533
2534 if (tempGpioData->type == ConfigType::GPIO)
2535 {
2536 if (gpioConfig.contains("LineName"))
2537 {
2538 tempGpioData->lineName = gpioConfig["LineName"];
2539 }
2540 else
2541 {
2542 phosphor::logging::log<phosphor::logging::level::ERR>(
2543 "The \'LineName\' field must be defined for GPIO "
2544 "configuration");
2545 return -1;
2546 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002547 if (gpioConfig.contains("Polarity"))
2548 {
2549 std::string polarity = gpioConfig["Polarity"];
2550 if (polarity == "ActiveLow")
2551 {
2552 tempGpioData->polarity = false;
2553 }
2554 else if (polarity == "ActiveHigh")
2555 {
2556 tempGpioData->polarity = true;
2557 }
2558 else
2559 {
2560 std::string errMsg =
2561 "Polarity defined but not properly setup. Please "
2562 "only ActiveHigh or ActiveLow. Currently set to " +
2563 polarity;
2564 phosphor::logging::log<phosphor::logging::level::ERR>(
2565 errMsg.c_str());
2566 return -1;
2567 }
2568 }
2569 else
2570 {
2571 std::string errMsg =
2572 "Polarity field not found for " + tempGpioData->lineName;
2573 phosphor::logging::log<phosphor::logging::level::ERR>(
2574 errMsg.c_str());
2575 return -1;
2576 }
Priyatharshan P70120512020-09-16 18:47:20 +05302577 }
2578 else
2579 {
2580 // if dbus based gpio config is defined read and update the dbus
2581 // params corresponding to the gpio config instance
2582 for (auto& [key, dbusParamName] : dbusParams)
2583 {
2584 if (!gpios.contains(dbusParamName))
2585 {
2586 std::string errMsg =
2587 "The " + dbusParamName +
2588 "field must be defined for Dbus configuration ";
2589 phosphor::logging::log<phosphor::logging::level::ERR>(
2590 errMsg.c_str());
2591 return -1;
2592 }
2593 }
2594 tempGpioData->dbusName = gpios[dbusParams[DbusConfigType::name]];
2595 tempGpioData->path = gpios[dbusParams[DbusConfigType::path]];
2596 tempGpioData->interface =
2597 gpios[dbusParams[DbusConfigType::interface]];
2598 tempGpioData->lineName =
2599 gpios[dbusParams[DbusConfigType::property]];
2600 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302601 }
2602
Priyatharshan P70120512020-09-16 18:47:20 +05302603 // read and store the timer values from json config to Timer Map
2604 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302605 {
Priyatharshan P70120512020-09-16 18:47:20 +05302606 if (timers.contains(key.c_str()))
2607 {
2608 timerValue = timers[key.c_str()];
2609 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302610 }
2611
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302612 return 0;
2613}
Priyatharshan P70120512020-09-16 18:47:20 +05302614inline static sdbusplus::bus::match::match powerButtonEventMonitor()
2615{
2616 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2617 bool value = false;
2618 std::string thresholdInterface;
2619 std::string event;
2620 boost::container::flat_map<std::string, std::variant<bool>>
2621 propertiesChanged;
2622 try
2623 {
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302624
Priyatharshan P70120512020-09-16 18:47:20 +05302625 msg.read(thresholdInterface, propertiesChanged);
2626
2627 if (propertiesChanged.empty())
2628 {
2629 return;
2630 }
2631 event = propertiesChanged.begin()->first;
2632
2633 if (event.empty() || event != powerButtonConfig.lineName)
2634 {
2635 return;
2636 }
2637
2638 value = std::get<bool>(propertiesChanged.begin()->second);
2639 }
2640 catch (std::exception& e)
2641 {
2642 phosphor::logging::log<phosphor::logging::level::ERR>(
2643 "exception during reading dbus property : powerButtonConfig");
2644 return;
2645 }
2646
2647 if (value == false)
2648 {
2649 powerButtonPressLog();
2650 powerButtonIface->set_property("ButtonPressed", true);
2651 if (!powerButtonMask)
2652 {
2653 sendPowerControlEvent(Event::powerButtonPressed);
2654 addRestartCause(RestartCause::powerButton);
2655 }
2656 else
2657 {
2658 phosphor::logging::log<phosphor::logging::level::ERR>(
2659 "power button press masked\n");
2660 }
2661 }
2662 else
2663 {
2664 powerButtonIface->set_property("ButtonPressed", false);
2665 }
2666 };
2667
2668 sdbusplus::bus::match::match pulseEventMatcher(
2669 static_cast<sdbusplus::bus::bus&>(*conn),
2670 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2671 "PropertiesChanged',arg0='" +
2672 powerButtonConfig.dbusName + "'",
2673 std::move(pulseEventMatcherCallback));
2674
2675 return pulseEventMatcher;
2676}
2677
2678inline static sdbusplus::bus::match::match resetButtonEventMonitor()
2679{
2680 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2681 bool value = false;
2682 std::string thresholdInterface;
2683 std::string event;
2684 boost::container::flat_map<std::string, std::variant<bool>>
2685 propertiesChanged;
2686 try
2687 {
2688 msg.read(thresholdInterface, propertiesChanged);
2689
2690 if (propertiesChanged.empty())
2691 {
2692 return;
2693 }
2694 event = propertiesChanged.begin()->first;
2695
2696 if (event.empty() || event != resetButtonConfig.lineName)
2697 {
2698 return;
2699 }
2700
2701 value = std::get<bool>(propertiesChanged.begin()->second);
2702 }
2703 catch (std::exception& e)
2704 {
2705 phosphor::logging::log<phosphor::logging::level::ERR>(
2706 "exception during reading dbus property : resetButtonConfig");
2707 return;
2708 }
2709
2710 if (value == false)
2711 {
2712 resetButtonPressLog();
2713 resetButtonIface->set_property("ButtonPressed", true);
2714 if (!resetButtonMask)
2715 {
2716 sendPowerControlEvent(Event::resetButtonPressed);
2717 addRestartCause(RestartCause::resetButton);
2718 }
2719 else
2720 {
2721 phosphor::logging::log<phosphor::logging::level::ERR>(
2722 "reset button press masked");
2723 }
2724 }
2725 else
2726 {
2727 resetButtonIface->set_property("ButtonPressed", false);
2728 }
2729 };
2730
2731 sdbusplus::bus::match::match pulseEventMatcher(
2732 static_cast<sdbusplus::bus::bus&>(*conn),
2733 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2734 "PropertiesChanged',arg0='" +
2735 resetButtonConfig.dbusName + "'",
2736 std::move(pulseEventMatcherCallback));
2737
2738 return pulseEventMatcher;
2739}
2740
2741inline static sdbusplus::bus::match::match powerOkEventMonitor()
2742{
2743 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2744 bool value = false;
2745 std::string thresholdInterface;
2746 std::string event;
2747 boost::container::flat_map<std::string, std::variant<bool>>
2748 propertiesChanged;
2749 try
2750 {
2751 msg.read(thresholdInterface, propertiesChanged);
2752
2753 if (propertiesChanged.empty())
2754 {
2755 return;
2756 }
2757 event = propertiesChanged.begin()->first;
2758
2759 if (event.empty() || event != powerOkConfig.lineName)
2760 {
2761 return;
2762 }
2763
2764 value = std::get<bool>(propertiesChanged.begin()->second);
2765 }
2766 catch (std::exception& e)
2767 {
2768 phosphor::logging::log<phosphor::logging::level::ERR>(
2769 "exception during reading dbus property : powerOkConfig");
2770 return;
2771 }
2772
2773 Event powerControlEvent =
2774 value ? Event::psPowerOKAssert : Event::psPowerOKDeAssert;
2775 sendPowerControlEvent(powerControlEvent);
2776 };
2777
2778 sdbusplus::bus::match::match pulseEventMatcher(
2779 static_cast<sdbusplus::bus::bus&>(*conn),
2780 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2781 "PropertiesChanged',arg0='" +
2782 powerOkConfig.dbusName + "'",
2783 std::move(pulseEventMatcherCallback));
2784
2785 return pulseEventMatcher;
2786}
2787
2788inline static sdbusplus::bus::match::match sioPwrGoodEventMonitor()
2789{
2790 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2791 bool value = false;
2792 std::string thresholdInterface;
2793 std::string event;
2794 boost::container::flat_map<std::string, std::variant<bool>>
2795 propertiesChanged;
2796 try
2797 {
2798 msg.read(thresholdInterface, propertiesChanged);
2799
2800 if (propertiesChanged.empty())
2801 {
2802 return;
2803 }
2804 event = propertiesChanged.begin()->first;
2805
2806 if (event.empty() || event != sioPwrGoodConfig.lineName)
2807 {
2808 return;
2809 }
2810
2811 value = std::get<bool>(propertiesChanged.begin()->second);
2812 }
2813 catch (std::exception& e)
2814 {
2815 phosphor::logging::log<phosphor::logging::level::ERR>(
2816 "exception during reading dbus property : sioPwrGoodConfig");
2817 return;
2818 }
2819
2820 Event powerControlEvent =
2821 value ? Event::sioPowerGoodAssert : Event::sioPowerGoodDeAssert;
2822
2823 sendPowerControlEvent(powerControlEvent);
2824 };
2825
2826 sdbusplus::bus::match::match pulseEventMatcher(
2827 static_cast<sdbusplus::bus::bus&>(*conn),
2828 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2829 "PropertiesChanged',arg0='" +
2830 sioPwrGoodConfig.dbusName + "'",
2831 std::move(pulseEventMatcherCallback));
2832
2833 return pulseEventMatcher;
2834}
2835
2836inline static sdbusplus::bus::match::match sioOnControlEventMonitor()
2837{
2838 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2839 bool value = false;
2840 std::string thresholdInterface;
2841 std::string event;
2842 boost::container::flat_map<std::string, std::variant<bool>>
2843 propertiesChanged;
2844 try
2845 {
2846 msg.read(thresholdInterface, propertiesChanged);
2847
2848 if (propertiesChanged.empty())
2849 {
2850 return;
2851 }
2852 event = propertiesChanged.begin()->first;
2853
2854 if (event.empty() || event != sioOnControlConfig.lineName)
2855 {
2856 return;
2857 }
2858
2859 value = std::get<bool>(propertiesChanged.begin()->second);
2860 }
2861 catch (std::exception& e)
2862 {
2863 phosphor::logging::log<phosphor::logging::level::ERR>(
2864 "exception during reading dbus property : sioOnControlConfig");
2865 return;
2866 }
2867
2868 std::string errMsg =
2869 "SIO_ONCONTROL value changed : " + std::to_string(value);
2870 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
2871 };
2872
2873 sdbusplus::bus::match::match pulseEventMatcher(
2874 static_cast<sdbusplus::bus::bus&>(*conn),
2875 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2876 "PropertiesChanged',arg0='" +
2877 sioOnControlConfig.dbusName + "'",
2878 std::move(pulseEventMatcherCallback));
2879
2880 return pulseEventMatcher;
2881}
2882
2883inline static sdbusplus::bus::match::match sioS5EventMonitor()
2884{
2885 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2886 bool value = false;
2887 std::string thresholdInterface;
2888 std::string event;
2889 boost::container::flat_map<std::string, std::variant<bool>>
2890 propertiesChanged;
2891 try
2892 {
2893 msg.read(thresholdInterface, propertiesChanged);
2894
2895 if (propertiesChanged.empty())
2896 {
2897 return;
2898 }
2899 event = propertiesChanged.begin()->first;
2900
2901 if (event.empty() || event != sioS5Config.lineName)
2902 {
2903 return;
2904 }
2905
2906 value = std::get<bool>(propertiesChanged.begin()->second);
2907 }
2908 catch (std::exception& e)
2909 {
2910 phosphor::logging::log<phosphor::logging::level::ERR>(
2911 "exception during reading dbus property : sioS5Config");
2912 return;
2913 }
2914
2915 Event powerControlEvent =
2916 value ? Event::sioS5DeAssert : Event::sioS5Assert;
2917 sendPowerControlEvent(powerControlEvent);
2918 };
2919
2920 sdbusplus::bus::match::match pulseEventMatcher(
2921 static_cast<sdbusplus::bus::bus&>(*conn),
2922 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2923 "PropertiesChanged',arg0='" +
2924 sioS5Config.dbusName + "'",
2925 std::move(pulseEventMatcherCallback));
2926
2927 return pulseEventMatcher;
2928}
2929
2930inline static sdbusplus::bus::match::match nmiButtonEventMonitor()
2931{
2932 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2933 bool value = false;
2934 std::string thresholdInterface;
2935 std::string event;
2936 boost::container::flat_map<std::string, std::variant<bool>>
2937 propertiesChanged;
2938 try
2939 {
2940 msg.read(thresholdInterface, propertiesChanged);
2941
2942 if (propertiesChanged.empty())
2943 {
2944 return;
2945 }
2946 event = propertiesChanged.begin()->first;
2947 if (event.empty() || event != nmiButtonConfig.lineName)
2948 {
2949 return;
2950 }
2951
2952 value = std::get<bool>(propertiesChanged.begin()->second);
2953 }
2954 catch (std::exception& e)
2955 {
2956 phosphor::logging::log<phosphor::logging::level::ERR>(
2957 "exception during reading dbus property : nmiButtonConfig");
2958 return;
2959 }
2960
2961 if (value)
2962 {
2963 nmiButtonIface->set_property("ButtonPressed", false);
2964 }
2965 else
2966 {
2967 nmiButtonPressLog();
2968 nmiButtonIface->set_property("ButtonPressed", true);
2969 if (nmiButtonMasked)
2970 {
2971 phosphor::logging::log<phosphor::logging::level::ERR>(
2972 "NMI button press masked");
2973 }
2974 else
2975 {
2976 setNmiSource();
2977 }
2978 }
2979 };
2980
2981 sdbusplus::bus::match::match pulseEventMatcher(
2982 static_cast<sdbusplus::bus::bus&>(*conn),
2983 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2984 "PropertiesChanged',arg0='" +
2985 nmiButtonConfig.dbusName + "'",
2986 std::move(pulseEventMatcherCallback));
2987
2988 return pulseEventMatcher;
2989}
2990
2991inline static sdbusplus::bus::match::match idButtonEventMonitor()
2992{
2993 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
2994 bool value = false;
2995 std::string thresholdInterface;
2996 std::string event;
2997 boost::container::flat_map<std::string, std::variant<bool>>
2998 propertiesChanged;
2999
3000 try
3001 {
3002
3003 msg.read(thresholdInterface, propertiesChanged);
3004
3005 if (propertiesChanged.empty())
3006 {
3007 return;
3008 }
3009 event = propertiesChanged.begin()->first;
3010
3011 if (event.empty() | event != idButtonConfig.lineName)
3012 {
3013 return;
3014 }
3015
3016 value = std::get<bool>(propertiesChanged.begin()->second);
3017 }
3018 catch (std::exception& e)
3019 {
3020 phosphor::logging::log<phosphor::logging::level::ERR>(
3021 "exception during reading dbus property : idButtonConfig");
3022 return;
3023 }
3024
3025 if (value)
3026 {
3027 idButtonIface->set_property("ButtonPressed", false);
3028 }
3029 else
3030 {
3031 idButtonIface->set_property("ButtonPressed", true);
3032 }
3033 };
3034
3035 sdbusplus::bus::match::match pulseEventMatcher(
3036 static_cast<sdbusplus::bus::bus&>(*conn),
3037 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
3038 "PropertiesChanged',arg0='" +
3039 idButtonConfig.dbusName + "'",
3040 std::move(pulseEventMatcherCallback));
3041
3042 return pulseEventMatcher;
3043}
3044
3045inline static sdbusplus::bus::match::match postCompleteEventMonitor()
3046{
3047 auto pulseEventMatcherCallback = [](sdbusplus::message::message& msg) {
3048 bool value = false;
3049 std::string thresholdInterface;
3050 std::string event;
3051 boost::container::flat_map<std::string, std::variant<bool>>
3052 propertiesChanged;
3053 try
3054 {
3055
3056 msg.read(thresholdInterface, propertiesChanged);
3057
3058 if (propertiesChanged.empty())
3059 {
3060 return;
3061 }
3062 event = propertiesChanged.begin()->first;
3063
3064 if (event.empty() | event != postCompleteConfig.lineName)
3065 {
3066 return;
3067 }
3068
3069 value = std::get<bool>(propertiesChanged.begin()->second);
3070 }
3071 catch (std::exception& e)
3072 {
3073 phosphor::logging::log<phosphor::logging::level::ERR>(
3074 "exception during reading dbus property : postCompleteConfig");
3075 return;
3076 }
3077
3078 if (value)
3079 {
3080 sendPowerControlEvent(Event::postCompleteDeAssert);
3081 osIface->set_property("OperatingSystemState",
3082 std::string("Inactive"));
3083 }
3084 else
3085 {
3086 sendPowerControlEvent(Event::postCompleteAssert);
3087 osIface->set_property("OperatingSystemState",
3088 std::string("Standby"));
3089 }
3090 };
3091
3092 sdbusplus::bus::match::match pulseEventMatcher(
3093 static_cast<sdbusplus::bus::bus&>(*conn),
3094 "type='signal',path='" + postCompleteConfig.path +
3095 "',interface='org.freedesktop.DBus.Properties',member='"
3096 "PropertiesChanged',arg0='" +
3097 postCompleteConfig.dbusName + "'",
3098 std::move(pulseEventMatcherCallback));
3099
3100 return pulseEventMatcher;
3101}
3102
3103int getProperty(ConfigData& configData)
3104{
3105 auto method = conn->new_method_call(
3106 configData.dbusName.c_str(), configData.path.c_str(),
3107 "org.freedesktop.DBus.Properties", "Get");
3108 method.append(configData.interface.c_str(), configData.lineName.c_str());
3109
3110 auto reply = conn->call(method);
3111 if (reply.is_method_error())
3112 {
3113 phosphor::logging::log<phosphor::logging::level::ERR>(
3114 "Error reading from Bus");
3115 return -1;
3116 }
3117 std::variant<int> resp;
3118 reply.read(resp);
3119 auto respValue = std::get_if<int>(&resp);
3120 if (!respValue)
3121 {
3122 phosphor::logging::log<phosphor::logging::level::ERR>(
3123 "Error reading response");
3124 return -1;
3125 }
3126 return (*respValue);
3127}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003128} // namespace power_control
3129
3130int main(int argc, char* argv[])
3131{
Lei YU92caa4c2021-02-23 16:59:25 +08003132 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05303133
3134 if (argc > 1)
3135 {
3136 node = argv[1];
3137 }
3138 std::string infoMsg =
3139 "Start Chassis power control service for host : " + node;
3140 phosphor::logging::log<phosphor::logging::level::INFO>(infoMsg.c_str());
3141
Lei YU92caa4c2021-02-23 16:59:25 +08003142 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003143
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303144 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08003145 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303146 {
Lei YU92caa4c2021-02-23 16:59:25 +08003147 std::string errMsg = "Host" + node + ": " + "Error in Parsing...";
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003148 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303149 }
Naveen Mosesec972d82021-07-16 21:19:23 +05303150 /* Currently for single host based systems additional busname is added
3151 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
3152 Going forward for single hosts the old bus name without zero numbering
3153 will be removed when all other applications adapted to the
3154 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
3155
3156 if (node == "0")
3157 {
3158 // Request all the dbus names
3159 conn->request_name(hostDbusName.c_str());
3160 conn->request_name(chassisDbusName.c_str());
3161 conn->request_name(osDbusName.c_str());
3162 conn->request_name(buttonDbusName.c_str());
3163 conn->request_name(nmiDbusName.c_str());
3164 conn->request_name(rstCauseDbusName.c_str());
3165 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303166
Zev Weissc4005bd2021-09-01 22:30:23 -05003167 hostDbusName += node;
3168 chassisDbusName += node;
3169 osDbusName += node;
3170 buttonDbusName += node;
3171 nmiDbusName += node;
3172 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003173
Priyatharshan P70120512020-09-16 18:47:20 +05303174 // Request all the dbus names
3175 conn->request_name(hostDbusName.c_str());
3176 conn->request_name(chassisDbusName.c_str());
3177 conn->request_name(osDbusName.c_str());
3178 conn->request_name(buttonDbusName.c_str());
3179 conn->request_name(nmiDbusName.c_str());
3180 conn->request_name(rstCauseDbusName.c_str());
3181
3182 if (sioPwrGoodConfig.lineName.empty() ||
3183 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05303184 {
Lei YU92caa4c2021-02-23 16:59:25 +08003185 sioEnabled = false;
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003186 phosphor::logging::log<phosphor::logging::level::INFO>(
3187 "SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05303188 }
3189
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003190 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303191 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003192 {
Priyatharshan P70120512020-09-16 18:47:20 +05303193 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
3194 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303195 {
3196 return -1;
3197 }
3198 }
Priyatharshan P70120512020-09-16 18:47:20 +05303199 else if (powerOkConfig.type == ConfigType::DBUS)
3200 {
3201
3202 static sdbusplus::bus::match::match powerOkEventMonitor =
3203 power_control::powerOkEventMonitor();
3204 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303205 else
3206 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003207 phosphor::logging::log<phosphor::logging::level::ERR>(
3208 "PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003209 return -1;
3210 }
3211
Lei YU92caa4c2021-02-23 16:59:25 +08003212 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003213 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05303214 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303215 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303216 {
Priyatharshan P70120512020-09-16 18:47:20 +05303217 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
3218 sioPowerGoodHandler, sioPowerGoodLine,
3219 sioPowerGoodEvent))
3220 {
3221 return -1;
3222 }
3223 }
3224 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
3225 {
3226 static sdbusplus::bus::match::match sioPwrGoodEventMonitor =
3227 power_control::sioPwrGoodEventMonitor();
3228 }
3229 else
3230 {
3231 phosphor::logging::log<phosphor::logging::level::ERR>(
3232 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303233 return -1;
3234 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003235
Priyatharshan P19c47a32020-08-12 18:16:43 +05303236 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303237 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303238 {
Priyatharshan P70120512020-09-16 18:47:20 +05303239 if (!requestGPIOEvents(sioOnControlConfig.lineName,
3240 sioOnControlHandler, sioOnControlLine,
3241 sioOnControlEvent))
3242 {
3243 return -1;
3244 }
3245 }
3246 else if (sioOnControlConfig.type == ConfigType::DBUS)
3247 {
3248 static sdbusplus::bus::match::match sioOnControlEventMonitor =
3249 power_control::sioOnControlEventMonitor();
3250 }
3251 else
3252 {
3253 phosphor::logging::log<phosphor::logging::level::ERR>(
3254 "sioOnControl name should be configured from json"
3255 "config file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303256 return -1;
3257 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003258
Priyatharshan P19c47a32020-08-12 18:16:43 +05303259 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303260 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303261 {
Priyatharshan P70120512020-09-16 18:47:20 +05303262 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
3263 sioS5Line, sioS5Event))
3264 {
3265 return -1;
3266 }
3267 }
3268 else if (sioS5Config.type == ConfigType::DBUS)
3269 {
3270 static sdbusplus::bus::match::match sioS5EventMonitor =
3271 power_control::sioS5EventMonitor();
3272 }
3273 else
3274 {
3275 phosphor::logging::log<phosphor::logging::level::ERR>(
3276 "sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303277 return -1;
3278 }
3279 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003280
3281 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303282 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003283 {
Priyatharshan P70120512020-09-16 18:47:20 +05303284 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
Lei YU92caa4c2021-02-23 16:59:25 +08003285 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303286 {
3287 return -1;
3288 }
3289 }
Priyatharshan P70120512020-09-16 18:47:20 +05303290 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303291 {
Priyatharshan P70120512020-09-16 18:47:20 +05303292 static sdbusplus::bus::match::match powerButtonEventMonitor =
3293 power_control::powerButtonEventMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003294 }
3295
3296 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303297 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003298 {
Priyatharshan P70120512020-09-16 18:47:20 +05303299 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
Lei YU92caa4c2021-02-23 16:59:25 +08003300 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303301 {
3302 return -1;
3303 }
3304 }
Priyatharshan P70120512020-09-16 18:47:20 +05303305 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303306 {
Priyatharshan P70120512020-09-16 18:47:20 +05303307 static sdbusplus::bus::match::match resetButtonEventMonitor =
3308 power_control::resetButtonEventMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003309 }
3310
3311 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303312 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303313 {
Priyatharshan P70120512020-09-16 18:47:20 +05303314 if (!nmiButtonConfig.lineName.empty())
3315 {
3316 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
3317 nmiButtonLine, nmiButtonEvent);
3318 }
3319 }
3320 else if (nmiButtonConfig.type == ConfigType::DBUS)
3321 {
3322 static sdbusplus::bus::match::match nmiButtonEventMonitor =
3323 power_control::nmiButtonEventMonitor();
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303324 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003325
3326 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303327 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303328 {
Priyatharshan P70120512020-09-16 18:47:20 +05303329 if (!idButtonConfig.lineName.empty())
3330 {
3331 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
3332 idButtonLine, idButtonEvent);
3333 }
3334 }
3335 else if (idButtonConfig.type == ConfigType::DBUS)
3336 {
3337 static sdbusplus::bus::match::match idButtonEventMonitor =
3338 power_control::idButtonEventMonitor();
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303339 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003340
Jason M. Billsfb957332021-01-28 13:18:46 -08003341#ifdef USE_PLT_RST
3342 sdbusplus::bus::match::match pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08003343 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08003344 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
3345 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08003346 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08003347#endif
3348
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003349 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05303350 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003351 {
Priyatharshan P70120512020-09-16 18:47:20 +05303352 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
Lei YU92caa4c2021-02-23 16:59:25 +08003353 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303354 {
3355 return -1;
3356 }
3357 }
Priyatharshan P70120512020-09-16 18:47:20 +05303358 else if (postCompleteConfig.type == ConfigType::DBUS)
3359 {
3360 static sdbusplus::bus::match::match postCompleteEventMonitor =
3361 power_control::postCompleteEventMonitor();
3362 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05303363 else
3364 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003365 phosphor::logging::log<phosphor::logging::level::ERR>(
3366 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003367 return -1;
3368 }
3369
3370 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05303371 if (!nmiOutConfig.lineName.empty())
3372 {
3373 setGPIOOutput(nmiOutConfig.lineName, 0, nmiOutLine);
3374 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003375
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003376 // Initialize POWER_OUT and RESET_OUT GPIO.
3377 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05303378 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003379 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07003380 if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
3381 line))
Priyatharshan P70120512020-09-16 18:47:20 +05303382 {
3383 return -1;
3384 }
3385 }
3386 else
3387 {
3388 phosphor::logging::log<phosphor::logging::level::ERR>(
3389 "powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003390 return -1;
3391 }
3392
Priyatharshan P70120512020-09-16 18:47:20 +05303393 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003394 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07003395 if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
3396 line))
Priyatharshan P70120512020-09-16 18:47:20 +05303397 {
3398 return -1;
3399 }
3400 }
3401 else
3402 {
3403 phosphor::logging::log<phosphor::logging::level::ERR>(
3404 "ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003405 return -1;
3406 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07003407 // Release line
3408 line.reset();
3409
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003410 // Initialize the power state
Lei YU92caa4c2021-02-23 16:59:25 +08003411 powerState = PowerState::off;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003412 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05303413
3414 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003415 {
Jean-Marie Verdun61b4a5b2021-09-19 08:53:28 -04003416 if (psPowerOKLine.get_value() > 0 ||
3417 sioPowerGoodLine.get_value() == sioPwrGoodConfig.polarity)
Priyatharshan P70120512020-09-16 18:47:20 +05303418 {
3419 powerState = PowerState::on;
3420 }
3421 }
3422 else
3423 {
3424 if (getProperty(powerOkConfig))
3425 {
3426 powerState = PowerState::on;
3427 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003428 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003429 // Initialize the power state storage
Lei YU92caa4c2021-02-23 16:59:25 +08003430 if (initializePowerStateStorage() < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003431 {
3432 return -1;
3433 }
3434
3435 // Check if we need to start the Power Restore policy
Lei YU92caa4c2021-02-23 16:59:25 +08003436 powerRestorePolicyCheck();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003437
Lei YU92caa4c2021-02-23 16:59:25 +08003438 if (nmiOutLine)
3439 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003440
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003441 phosphor::logging::log<phosphor::logging::level::INFO>(
3442 "Initializing power state. ");
Lei YU92caa4c2021-02-23 16:59:25 +08003443 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003444
3445 // Power Control Service
3446 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003447 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003448
3449 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303450 hostIface =
3451 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
3452 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003453 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08003454 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003455 "RequestedHostTransition",
3456 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
3457 [](const std::string& requested, std::string& resp) {
3458 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
3459 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003460 // if power button is masked, ignore this
3461 if (!powerButtonMask)
3462 {
3463 sendPowerControlEvent(Event::gracefulPowerOffRequest);
3464 addRestartCause(RestartCause::command);
3465 }
3466 else
3467 {
3468 phosphor::logging::log<phosphor::logging::level::INFO>(
3469 "Power Button Masked.");
3470 throw std::invalid_argument("Transition Request Masked");
3471 return 0;
3472 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003473 }
3474 else if (requested ==
3475 "xyz.openbmc_project.State.Host.Transition.On")
3476 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003477 // if power button is masked, ignore this
3478 if (!powerButtonMask)
3479 {
3480 sendPowerControlEvent(Event::powerOnRequest);
3481 addRestartCause(RestartCause::command);
3482 }
3483 else
3484 {
3485 phosphor::logging::log<phosphor::logging::level::INFO>(
3486 "Power Button Masked.");
3487 throw std::invalid_argument("Transition Request Masked");
3488 return 0;
3489 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003490 }
3491 else if (requested ==
3492 "xyz.openbmc_project.State.Host.Transition.Reboot")
3493 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003494 // if power button is masked, ignore this
3495 if (!powerButtonMask)
3496 {
3497 sendPowerControlEvent(Event::powerCycleRequest);
3498 addRestartCause(RestartCause::command);
3499 }
3500 else
3501 {
3502 phosphor::logging::log<phosphor::logging::level::INFO>(
3503 "Power Button Masked.");
3504 throw std::invalid_argument("Transition Request Masked");
3505 return 0;
3506 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003507 }
3508 else if (requested == "xyz.openbmc_project.State.Host.Transition."
3509 "GracefulWarmReboot")
3510 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003511 // if reset button is masked, ignore this
3512 if (!resetButtonMask)
3513 {
3514 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
3515 addRestartCause(RestartCause::command);
3516 }
3517 else
3518 {
3519 phosphor::logging::log<phosphor::logging::level::INFO>(
3520 "Reset Button Masked.");
3521 throw std::invalid_argument("Transition Request Masked");
3522 return 0;
3523 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003524 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003525 else if (requested == "xyz.openbmc_project.State.Host.Transition."
3526 "ForceWarmReboot")
3527 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07003528 // if reset button is masked, ignore this
3529 if (!resetButtonMask)
3530 {
3531 sendPowerControlEvent(Event::resetRequest);
3532 addRestartCause(RestartCause::command);
3533 }
3534 else
3535 {
3536 phosphor::logging::log<phosphor::logging::level::INFO>(
3537 "Reset Button Masked.");
3538 throw std::invalid_argument("Transition Request Masked");
3539 return 0;
3540 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08003541 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003542 else
3543 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003544 phosphor::logging::log<phosphor::logging::level::ERR>(
3545 "Unrecognized host state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003546 throw std::invalid_argument("Unrecognized Transition Request");
3547 return 0;
3548 }
3549 resp = requested;
3550 return 1;
3551 });
Lei YU92caa4c2021-02-23 16:59:25 +08003552 hostIface->register_property("CurrentHostState",
3553 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003554
Lei YU92caa4c2021-02-23 16:59:25 +08003555 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003556
3557 // Chassis Control Service
3558 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003559 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003560
3561 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003562 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05303563 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003564 "xyz.openbmc_project.State.Chassis");
3565
Lei YU92caa4c2021-02-23 16:59:25 +08003566 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003567 "RequestedPowerTransition",
3568 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
3569 [](const std::string& requested, std::string& resp) {
3570 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
3571 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003572 // if power button is masked, ignore this
3573 if (!powerButtonMask)
3574 {
3575 sendPowerControlEvent(Event::powerOffRequest);
3576 addRestartCause(RestartCause::command);
3577 }
3578 else
3579 {
3580 phosphor::logging::log<phosphor::logging::level::INFO>(
3581 "Power Button Masked.");
3582 throw std::invalid_argument("Transition Request Masked");
3583 return 0;
3584 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003585 }
3586 else if (requested ==
3587 "xyz.openbmc_project.State.Chassis.Transition.On")
3588 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003589 // if power button is masked, ignore this
3590 if (!powerButtonMask)
3591 {
3592 sendPowerControlEvent(Event::powerOnRequest);
3593 addRestartCause(RestartCause::command);
3594 }
3595 else
3596 {
3597 phosphor::logging::log<phosphor::logging::level::INFO>(
3598 "Power Button Masked.");
3599 throw std::invalid_argument("Transition Request Masked");
3600 return 0;
3601 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003602 }
3603 else if (requested ==
3604 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3605 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003606 // if power button is masked, ignore this
3607 if (!powerButtonMask)
3608 {
3609 sendPowerControlEvent(Event::powerCycleRequest);
3610 addRestartCause(RestartCause::command);
3611 }
3612 else
3613 {
3614 phosphor::logging::log<phosphor::logging::level::INFO>(
3615 "Power Button Masked.");
3616 throw std::invalid_argument("Transition Request Masked");
3617 return 0;
3618 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003619 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003620 else
3621 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003622 phosphor::logging::log<phosphor::logging::level::ERR>(
3623 "Unrecognized chassis state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003624 throw std::invalid_argument("Unrecognized Transition Request");
3625 return 0;
3626 }
3627 resp = requested;
3628 return 1;
3629 });
Lei YU92caa4c2021-02-23 16:59:25 +08003630 chassisIface->register_property("CurrentPowerState",
3631 std::string(getChassisState(powerState)));
3632 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003633
Lei YU92caa4c2021-02-23 16:59:25 +08003634 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003635
Vijay Khemka04175c22020-10-09 14:28:11 -07003636#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003637 // Chassis System Service
3638 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003639 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003640
3641 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003642 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003643 "/xyz/openbmc_project/state/chassis_system0",
3644 "xyz.openbmc_project.State.Chassis");
3645
Lei YU92caa4c2021-02-23 16:59:25 +08003646 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003647 "RequestedPowerTransition",
3648 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3649 [](const std::string& requested, std::string& resp) {
3650 if (requested ==
3651 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3652 {
Lei YU92caa4c2021-02-23 16:59:25 +08003653 systemReset();
3654 addRestartCause(RestartCause::command);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003655 }
3656 else
3657 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003658 phosphor::logging::log<phosphor::logging::level::ERR>(
3659 "Unrecognized chassis system state transition request.");
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003660 throw std::invalid_argument("Unrecognized Transition Request");
3661 return 0;
3662 }
3663 resp = requested;
3664 return 1;
3665 });
Lei YU92caa4c2021-02-23 16:59:25 +08003666 chassisSysIface->register_property(
3667 "CurrentPowerState", std::string(getChassisState(powerState)));
3668 chassisSysIface->register_property("LastStateChangeTime",
3669 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003670
Lei YU92caa4c2021-02-23 16:59:25 +08003671 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003672
Naveen Moses117c34e2021-05-26 20:10:51 +05303673 if (!slotPowerConfig.lineName.empty())
3674 {
3675 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3676 {
3677 return -1;
3678 }
3679
3680 slotPowerState = SlotPowerState::off;
3681 if (slotPowerLine.get_value() > 0)
3682 {
3683 slotPowerState = SlotPowerState::on;
3684 }
3685
3686 chassisSlotIface = chassisSysServer.add_interface(
3687 "/xyz/openbmc_project/state/chassis_system" + node,
3688 "xyz.openbmc_project.State.Chassis");
3689 chassisSlotIface->register_property(
3690 "RequestedPowerTransition",
3691 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3692 [](const std::string& requested, std::string& resp) {
3693 if (requested ==
3694 "xyz.openbmc_project.State.Chassis.Transition.On")
3695 {
3696 slotPowerOn();
3697 }
3698 else if (requested ==
3699 "xyz.openbmc_project.State.Chassis.Transition.Off")
3700 {
3701 slotPowerOff();
3702 }
3703 else if (requested == "xyz.openbmc_project.State.Chassis."
3704 "Transition.PowerCycle")
3705 {
3706 slotPowerCycle();
3707 }
3708 else
3709 {
3710 phosphor::logging::log<phosphor::logging::level::ERR>(
3711 "Unrecognized chassis system state transition "
3712 "request.\n");
3713 throw std::invalid_argument(
3714 "Unrecognized Transition Request");
3715 return 0;
3716 }
3717 resp = requested;
3718 return 1;
3719 });
3720 chassisSlotIface->register_property(
3721 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3722 chassisSlotIface->register_property("LastStateChangeTime",
3723 getCurrentTimeMs());
3724 chassisSlotIface->initialize();
3725 }
3726#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003727 // Buttons Service
3728 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003729 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003730
Priyatharshan P70120512020-09-16 18:47:20 +05303731 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003732 {
Priyatharshan P70120512020-09-16 18:47:20 +05303733 // Power Button Interface
3734 power_control::powerButtonIface = buttonsServer.add_interface(
3735 "/xyz/openbmc_project/chassis/buttons/power",
3736 "xyz.openbmc_project.Chassis.Buttons");
3737
3738 powerButtonIface->register_property(
3739 "ButtonMasked", false, [](const bool requested, bool& current) {
3740 if (requested)
3741 {
3742 if (powerButtonMask)
3743 {
3744 return 1;
3745 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003746 if (!setGPIOOutput(powerOutConfig.lineName,
3747 !powerOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303748 powerButtonMask))
3749 {
3750 throw std::runtime_error("Failed to request GPIO");
3751 return 0;
3752 }
3753 phosphor::logging::log<phosphor::logging::level::INFO>(
3754 "Power Button Masked.");
3755 }
3756 else
3757 {
3758 if (!powerButtonMask)
3759 {
3760 return 1;
3761 }
3762 phosphor::logging::log<phosphor::logging::level::INFO>(
3763 "Power Button Un-masked");
3764 powerButtonMask.reset();
3765 }
3766 // Update the mask setting
3767 current = requested;
3768 return 1;
3769 });
3770
3771 // Check power button state
3772 bool powerButtonPressed;
3773 if (powerButtonConfig.type == ConfigType::GPIO)
3774 {
3775 powerButtonPressed = powerButtonLine.get_value() == 0;
3776 }
3777 else
3778 {
3779 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3780 }
3781
3782 powerButtonIface->register_property("ButtonPressed",
3783 powerButtonPressed);
3784
3785 powerButtonIface->initialize();
3786 }
3787
3788 if (!resetButtonConfig.lineName.empty())
3789 {
3790 // Reset Button Interface
3791
Lei YU92caa4c2021-02-23 16:59:25 +08003792 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003793 "/xyz/openbmc_project/chassis/buttons/reset",
3794 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003795
Lei YU92caa4c2021-02-23 16:59:25 +08003796 resetButtonIface->register_property(
John Wang6c090072020-09-30 13:32:16 +08003797 "ButtonMasked", false, [](const bool requested, bool& current) {
3798 if (requested)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003799 {
Lei YU92caa4c2021-02-23 16:59:25 +08003800 if (resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003801 {
3802 return 1;
3803 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003804 if (!setGPIOOutput(resetOutConfig.lineName,
3805 !resetOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303806 resetButtonMask))
John Wang6c090072020-09-30 13:32:16 +08003807 {
3808 throw std::runtime_error("Failed to request GPIO");
3809 return 0;
3810 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003811 phosphor::logging::log<phosphor::logging::level::INFO>(
3812 "Reset Button Masked.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003813 }
John Wang6c090072020-09-30 13:32:16 +08003814 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003815 {
Lei YU92caa4c2021-02-23 16:59:25 +08003816 if (!resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003817 {
3818 return 1;
3819 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003820 phosphor::logging::log<phosphor::logging::level::INFO>(
3821 "Reset Button Un-masked");
Lei YU92caa4c2021-02-23 16:59:25 +08003822 resetButtonMask.reset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003823 }
John Wang6c090072020-09-30 13:32:16 +08003824 // Update the mask setting
3825 current = requested;
3826 return 1;
3827 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003828
John Wang6c090072020-09-30 13:32:16 +08003829 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303830 bool resetButtonPressed;
3831 if (resetButtonConfig.type == ConfigType::GPIO)
3832 {
3833 resetButtonPressed = resetButtonLine.get_value() == 0;
3834 }
3835 else
3836 {
3837 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3838 }
3839
Lei YU92caa4c2021-02-23 16:59:25 +08003840 resetButtonIface->register_property("ButtonPressed",
3841 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003842
Lei YU92caa4c2021-02-23 16:59:25 +08003843 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003844 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003845
Lei YU92caa4c2021-02-23 16:59:25 +08003846 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003847 {
3848 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003849 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003850 "/xyz/openbmc_project/chassis/buttons/nmi",
3851 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003852
Lei YU92caa4c2021-02-23 16:59:25 +08003853 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003854 "ButtonMasked", false, [](const bool requested, bool& current) {
Lei YU92caa4c2021-02-23 16:59:25 +08003855 if (nmiButtonMasked == requested)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003856 {
3857 // NMI button mask is already set as requested, so no change
3858 return 1;
3859 }
3860 if (requested)
3861 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003862 phosphor::logging::log<phosphor::logging::level::INFO>(
3863 "NMI Button Masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003864 nmiButtonMasked = true;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003865 }
3866 else
3867 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003868 phosphor::logging::log<phosphor::logging::level::INFO>(
3869 "NMI Button Un-masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003870 nmiButtonMasked = false;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003871 }
3872 // Update the mask setting
Lei YU92caa4c2021-02-23 16:59:25 +08003873 current = nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003874 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003875 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003876
Vijay Khemka33a532d2019-11-14 16:50:35 -08003877 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303878 bool nmiButtonPressed;
3879 if (nmiButtonConfig.type == ConfigType::GPIO)
3880 {
3881 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3882 }
3883 else
3884 {
3885 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3886 }
3887
Lei YU92caa4c2021-02-23 16:59:25 +08003888 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003889
Lei YU92caa4c2021-02-23 16:59:25 +08003890 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003891 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003892
Lei YU92caa4c2021-02-23 16:59:25 +08003893 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003894 {
3895 // NMI out Service
3896 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003897 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003898
Vijay Khemka33a532d2019-11-14 16:50:35 -08003899 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303900 nmiOutIface = nmiOutServer.add_interface(
3901 "/xyz/openbmc_project/control/host" + node + "/nmi",
3902 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003903 nmiOutIface->register_method("NMI", nmiReset);
3904 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003905 }
Chen Yugang174ec662019-08-19 19:58:49 +08003906
Lei YU92caa4c2021-02-23 16:59:25 +08003907 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003908 {
3909 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003910 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003911 "/xyz/openbmc_project/chassis/buttons/id",
3912 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003913
Vijay Khemka33a532d2019-11-14 16:50:35 -08003914 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303915 bool idButtonPressed;
3916 if (idButtonConfig.type == ConfigType::GPIO)
3917 {
3918 idButtonPressed = idButtonLine.get_value() == 0;
3919 }
3920 else
3921 {
3922 idButtonPressed = getProperty(idButtonConfig) == 0;
3923 }
3924
Lei YU92caa4c2021-02-23 16:59:25 +08003925 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003926
Lei YU92caa4c2021-02-23 16:59:25 +08003927 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003928 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003929
3930 // OS State Service
3931 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003932 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003933
3934 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003935 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003936 "/xyz/openbmc_project/state/os",
3937 "xyz.openbmc_project.State.OperatingSystem.Status");
3938
3939 // Get the initial OS state based on POST complete
3940 // 0: Asserted, OS state is "Standby" (ready to boot)
3941 // 1: De-Asserted, OS state is "Inactive"
Priyatharshan P70120512020-09-16 18:47:20 +05303942 std::string osState;
3943 if (postCompleteConfig.type == ConfigType::GPIO)
3944 {
3945 osState = postCompleteLine.get_value() > 0 ? "Inactive" : "Standby";
3946 }
3947 else
3948 {
3949 osState = getProperty(postCompleteConfig) > 0 ? "Inactive" : "Standby";
3950 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003951
Lei YU92caa4c2021-02-23 16:59:25 +08003952 osIface->register_property("OperatingSystemState", std::string(osState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003953
Lei YU92caa4c2021-02-23 16:59:25 +08003954 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003955
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003956 // Restart Cause Service
3957 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003958 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003959
3960 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003961 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303962 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003963 "xyz.openbmc_project.Control.Host.RestartCause");
3964
Lei YU92caa4c2021-02-23 16:59:25 +08003965 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003966 "RestartCause",
3967 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3968
Lei YU92caa4c2021-02-23 16:59:25 +08003969 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003970 "RequestedRestartCause",
3971 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3972 [](const std::string& requested, std::string& resp) {
3973 if (requested ==
3974 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3975 {
Lei YU92caa4c2021-02-23 16:59:25 +08003976 addRestartCause(RestartCause::watchdog);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003977 }
3978 else
3979 {
3980 throw std::invalid_argument(
3981 "Unrecognized RestartCause Request");
3982 return 0;
3983 }
3984
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003985 std::string logMsg = "RestartCause requested: " + requested;
3986 phosphor::logging::log<phosphor::logging::level::INFO>(
3987 logMsg.c_str());
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003988 resp = requested;
3989 return 1;
3990 });
3991
Lei YU92caa4c2021-02-23 16:59:25 +08003992 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003993
Lei YU92caa4c2021-02-23 16:59:25 +08003994 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003995
Lei YU92caa4c2021-02-23 16:59:25 +08003996 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003997
3998 return 0;
3999}