blob: c24fe926a762610109d0601df6e42a080844aa39 [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
Zev Weiss676ef2c2021-09-02 21:54:02 -05001064static void waitForGPIOEvent(const std::string& name,
1065 const std::function<void(bool)>& eventHandler,
1066 gpiod::line& line,
1067 boost::asio::posix::stream_descriptor& event)
1068{
1069 event.async_wait(
1070 boost::asio::posix::stream_descriptor::wait_read,
1071 [&name, eventHandler, &line,
1072 &event](const boost::system::error_code ec) {
1073 if (ec)
1074 {
1075 std::string errMsg =
1076 name + " fd handler error: " + ec.message();
1077 phosphor::logging::log<phosphor::logging::level::ERR>(
1078 errMsg.c_str());
1079 // TODO: throw here to force power-control to restart?
1080 return;
1081 }
1082 gpiod::line_event line_event = line.event_read();
1083 eventHandler(line_event.event_type ==
1084 gpiod::line_event::RISING_EDGE);
1085 waitForGPIOEvent(name, eventHandler, line, event);
1086 });
1087}
1088
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001089static bool requestGPIOEvents(
Zev Weiss676ef2c2021-09-02 21:54:02 -05001090 const std::string& name, const std::function<void(bool)>& handler,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001091 gpiod::line& gpioLine,
1092 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
1093{
1094 // Find the GPIO line
1095 gpioLine = gpiod::find_line(name);
1096 if (!gpioLine)
1097 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001098 std::string errMsg = "Failed to find the " + name + " line";
1099 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001100 return false;
1101 }
1102
1103 try
1104 {
1105 gpioLine.request(
1106 {"power-control", gpiod::line_request::EVENT_BOTH_EDGES});
1107 }
1108 catch (std::exception&)
1109 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001110 std::string errMsg = "Failed to request events for " + name;
1111 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001112 return false;
1113 }
1114
1115 int gpioLineFd = gpioLine.event_get_fd();
1116 if (gpioLineFd < 0)
1117 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001118 std::string errMsg = "Failed to name " + name + " fd";
1119 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001120 return false;
1121 }
1122
1123 gpioEventDescriptor.assign(gpioLineFd);
1124
Zev Weiss676ef2c2021-09-02 21:54:02 -05001125 waitForGPIOEvent(name, handler, gpioLine, gpioEventDescriptor);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001126 return true;
1127}
1128
1129static bool setGPIOOutput(const std::string& name, const int value,
1130 gpiod::line& gpioLine)
1131{
1132 // Find the GPIO line
1133 gpioLine = gpiod::find_line(name);
1134 if (!gpioLine)
1135 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001136 std::string errMsg = "Failed to find the " + name + " line";
1137 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001138 return false;
1139 }
1140
1141 // Request GPIO output to specified value
1142 try
1143 {
1144 gpioLine.request({__FUNCTION__, gpiod::line_request::DIRECTION_OUTPUT},
1145 value);
1146 }
1147 catch (std::exception&)
1148 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001149 std::string errMsg = "Failed to request " + name + " output";
1150 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001151 return false;
1152 }
1153
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001154 std::string logMsg = name + " set to " + std::to_string(value);
1155 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001156 return true;
1157}
1158
1159static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1160 const std::string& name, const int value,
1161 const int durationMs)
1162{
1163 // Set the masked GPIO line to the specified value
1164 maskedGPIOLine.set_value(value);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001165 std::string logMsg = name + " set to " + std::to_string(value);
1166 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001167 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001168 gpioAssertTimer.async_wait([maskedGPIOLine, value,
1169 name](const boost::system::error_code ec) {
1170 // Set the masked GPIO line back to the opposite value
1171 maskedGPIOLine.set_value(!value);
1172 std::string logMsg = name + " released";
1173 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
1174 if (ec)
1175 {
1176 // operation_aborted is expected if timer is canceled before
1177 // completion.
1178 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001179 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001180 std::string errMsg =
1181 name + " async_wait failed: " + ec.message();
1182 phosphor::logging::log<phosphor::logging::level::ERR>(
1183 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001184 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001185 }
1186 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001187 return 0;
1188}
1189
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001190static int setGPIOOutputForMs(const ConfigData& config, const int value,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001191 const int durationMs)
1192{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001193 int polarizedvalue;
1194 if (!config.polarity)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001195 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001196 polarizedvalue = value;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001197 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001198 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001199 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001200 polarizedvalue = !value;
1201 }
1202 // If the requested GPIO is masked, use the mask line to set the output
1203 if (powerButtonMask && config.lineName == powerOutConfig.lineName)
1204 {
1205 return setMaskedGPIOOutputForMs(powerButtonMask, config.lineName,
1206 polarizedvalue, durationMs);
1207 }
1208 if (resetButtonMask && config.lineName == resetOutConfig.lineName)
1209 {
1210 return setMaskedGPIOOutputForMs(resetButtonMask, config.lineName,
1211 polarizedvalue, durationMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001212 }
1213
1214 // No mask set, so request and set the GPIO normally
1215 gpiod::line gpioLine;
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001216 if (!setGPIOOutput(config.lineName, polarizedvalue, gpioLine))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001217 {
1218 return -1;
1219 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001220 const std::string name = config.lineName;
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001221
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001222 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001223 gpioAssertTimer.async_wait([gpioLine, polarizedvalue,
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001224 name](const boost::system::error_code ec) {
1225 // Set the GPIO line back to the opposite value
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001226 gpioLine.set_value(!polarizedvalue);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001227 std::string logMsg = name + " released";
1228 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
1229 if (ec)
1230 {
1231 // operation_aborted is expected if timer is canceled before
1232 // completion.
1233 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001234 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001235 std::string errMsg =
1236 name + " async_wait failed: " + ec.message();
1237 phosphor::logging::log<phosphor::logging::level::ERR>(
1238 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001239 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001240 }
1241 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001242 return 0;
1243}
1244
1245static void powerOn()
1246{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001247 setGPIOOutputForMs(powerOutConfig, 0, TimerMap["powerPulseTimeMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001248}
Naveen Moses117c34e2021-05-26 20:10:51 +05301249#ifdef CHASSIS_SYSTEM_RESET
1250static int slotPowerOn()
1251{
1252 if (power_control::slotPowerState != power_control::SlotPowerState::on)
1253 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001254
Naveen Moses117c34e2021-05-26 20:10:51 +05301255 slotPowerLine.set_value(1);
1256
1257 if (slotPowerLine.get_value() > 0)
1258 {
1259 setSlotPowerState(SlotPowerState::on);
1260 phosphor::logging::log<phosphor::logging::level::INFO>(
1261 "Slot Power is switched On\n");
1262 }
1263 else
1264 {
1265 return -1;
1266 }
1267 }
1268 else
1269 {
1270 phosphor::logging::log<phosphor::logging::level::INFO>(
1271 "Slot Power is already in 'On' state\n");
1272 return -1;
1273 }
1274 return 0;
1275}
1276static int slotPowerOff()
1277{
1278 if (power_control::slotPowerState != power_control::SlotPowerState::off)
1279 {
1280 slotPowerLine.set_value(0);
1281
1282 if (!(slotPowerLine.get_value() > 0))
1283 {
1284 setSlotPowerState(SlotPowerState::off);
1285 setPowerState(PowerState::off);
1286 phosphor::logging::log<phosphor::logging::level::INFO>(
1287 "Slot Power is switched Off\n");
1288 }
1289 else
1290 {
1291 return -1;
1292 }
1293 }
1294 else
1295 {
1296 phosphor::logging::log<phosphor::logging::level::INFO>(
1297 "Slot Power is already in 'Off' state\n");
1298 return -1;
1299 }
1300 return 0;
1301}
1302static void slotPowerCycle()
1303{
1304 phosphor::logging::log<phosphor::logging::level::INFO>(
1305 "Slot Power Cycle started\n");
1306 slotPowerOff();
1307 slotPowerCycleTimer.expires_after(
1308 std::chrono::milliseconds(TimerMap["slotPowerCycleTimeMs"]));
1309 slotPowerCycleTimer.async_wait([](const boost::system::error_code ec) {
1310 if (ec)
1311 {
1312 if (ec != boost::asio::error::operation_aborted)
1313 {
1314 std::string errMsg =
1315 "Slot Power cycle timer async_wait failed: " + ec.message();
1316 phosphor::logging::log<phosphor::logging::level::ERR>(
1317 errMsg.c_str());
1318 }
1319 phosphor::logging::log<phosphor::logging::level::INFO>(
1320 "Slot Power cycle timer canceled\n");
1321 return;
1322 }
1323 phosphor::logging::log<phosphor::logging::level::INFO>(
1324 "Slot Power cycle timer completed\n");
1325 slotPowerOn();
1326 phosphor::logging::log<phosphor::logging::level::INFO>(
1327 "Slot Power Cycle Completed\n");
1328 });
1329}
1330#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001331static void gracefulPowerOff()
1332{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001333 setGPIOOutputForMs(powerOutConfig, 0, TimerMap["powerPulseTimeMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001334}
1335
1336static void forcePowerOff()
1337{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001338 if (setGPIOOutputForMs(powerOutConfig, 0, TimerMap["forceOffPulseTimeMs"]) <
1339 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001340 {
1341 return;
1342 }
1343
1344 // If the force off timer expires, then the PCH power-button override
1345 // failed, so attempt the Unconditional Powerdown SMBus command.
1346 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1347 if (ec)
1348 {
1349 // operation_aborted is expected if timer is canceled before
1350 // completion.
1351 if (ec != boost::asio::error::operation_aborted)
1352 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001353 std::string errMsg =
1354 "Force power off async_wait failed: " + ec.message();
1355 phosphor::logging::log<phosphor::logging::level::ERR>(
1356 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001357 }
1358 return;
1359 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001360
1361 phosphor::logging::log<phosphor::logging::level::INFO>(
1362 "PCH Power-button override failed. Issuing Unconditional Powerdown "
1363 "SMBus command.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001364 const static constexpr size_t pchDevBusAddress = 3;
1365 const static constexpr size_t pchDevSlaveAddress = 0x44;
1366 const static constexpr size_t pchCmdReg = 0;
1367 const static constexpr size_t pchPowerDownCmd = 0x02;
1368 if (i2cSet(pchDevBusAddress, pchDevSlaveAddress, pchCmdReg,
1369 pchPowerDownCmd) < 0)
1370 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001371 phosphor::logging::log<phosphor::logging::level::ERR>(
1372 "Unconditional Powerdown command failed! Not sure what to do "
1373 "now.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001374 }
1375 });
1376}
1377
1378static void reset()
1379{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001380 setGPIOOutputForMs(resetOutConfig, 0, TimerMap["resetPulseTimeMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001381}
1382
1383static void gracefulPowerOffTimerStart()
1384{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001385 phosphor::logging::log<phosphor::logging::level::INFO>(
1386 "Graceful power-off timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001387 gracefulPowerOffTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301388 std::chrono::seconds(TimerMap["gracefulPowerOffTimeS"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001389 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1390 if (ec)
1391 {
1392 // operation_aborted is expected if timer is canceled before
1393 // completion.
1394 if (ec != boost::asio::error::operation_aborted)
1395 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001396 std::string errMsg =
1397 "Graceful power-off async_wait failed: " + ec.message();
1398 phosphor::logging::log<phosphor::logging::level::ERR>(
1399 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001400 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001401 phosphor::logging::log<phosphor::logging::level::INFO>(
1402 "Graceful power-off timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001403 return;
1404 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001405 phosphor::logging::log<phosphor::logging::level::INFO>(
1406 "Graceful power-off timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001407 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1408 });
1409}
1410
1411static void powerCycleTimerStart()
1412{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001413 phosphor::logging::log<phosphor::logging::level::INFO>(
1414 "Power-cycle timer started");
Priyatharshan P70120512020-09-16 18:47:20 +05301415 powerCycleTimer.expires_after(
1416 std::chrono::milliseconds(TimerMap["powerCycleTimeMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001417 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1418 if (ec)
1419 {
1420 // operation_aborted is expected if timer is canceled before
1421 // completion.
1422 if (ec != boost::asio::error::operation_aborted)
1423 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001424 std::string errMsg =
1425 "Power-cycle async_wait failed: " + ec.message();
1426 phosphor::logging::log<phosphor::logging::level::ERR>(
1427 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001428 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001429 phosphor::logging::log<phosphor::logging::level::INFO>(
1430 "Power-cycle timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001431 return;
1432 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001433 phosphor::logging::log<phosphor::logging::level::INFO>(
1434 "Power-cycle timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001435 sendPowerControlEvent(Event::powerCycleTimerExpired);
1436 });
1437}
1438
1439static void psPowerOKWatchdogTimerStart()
1440{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001441 phosphor::logging::log<phosphor::logging::level::INFO>(
1442 "power supply power OK watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001443 psPowerOKWatchdogTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301444 std::chrono::milliseconds(TimerMap["psPowerOKWatchdogTimeMs"]));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001445 psPowerOKWatchdogTimer.async_wait([](const boost::system::error_code ec) {
1446 if (ec)
1447 {
1448 // operation_aborted is expected if timer is canceled before
1449 // completion.
1450 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001451 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001452 std::string errMsg =
1453 "power supply power OK watchdog async_wait failed: " +
1454 ec.message();
1455 phosphor::logging::log<phosphor::logging::level::ERR>(
1456 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001457 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001458 phosphor::logging::log<phosphor::logging::level::INFO>(
1459 "power supply power OK watchdog timer canceled");
1460 return;
1461 }
1462 phosphor::logging::log<phosphor::logging::level::INFO>(
1463 "power supply power OK watchdog timer expired");
1464 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1465 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001466}
1467
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001468static void warmResetCheckTimerStart()
1469{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001470 phosphor::logging::log<phosphor::logging::level::INFO>(
1471 "Warm reset check timer started");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001472 warmResetCheckTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301473 std::chrono::milliseconds(TimerMap["warmResetCheckTimeMs"]));
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001474 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1475 if (ec)
1476 {
1477 // operation_aborted is expected if timer is canceled before
1478 // completion.
1479 if (ec != boost::asio::error::operation_aborted)
1480 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001481 std::string errMsg =
1482 "Warm reset check async_wait failed: " + ec.message();
1483 phosphor::logging::log<phosphor::logging::level::ERR>(
1484 errMsg.c_str());
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001485 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001486 phosphor::logging::log<phosphor::logging::level::INFO>(
1487 "Warm reset check timer canceled");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001488 return;
1489 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001490 phosphor::logging::log<phosphor::logging::level::INFO>(
1491 "Warm reset check timer completed");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001492 sendPowerControlEvent(Event::warmResetDetected);
1493 });
1494}
1495
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001496static void pohCounterTimerStart()
1497{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001498 phosphor::logging::log<phosphor::logging::level::INFO>("POH timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001499 // Set the time-out as 1 hour, to align with POH command in ipmid
1500 pohCounterTimer.expires_after(std::chrono::hours(1));
1501 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1502 if (ec)
1503 {
1504 // operation_aborted is expected if timer is canceled before
1505 // completion.
1506 if (ec != boost::asio::error::operation_aborted)
1507 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001508 std::string errMsg =
1509 "POH timer async_wait failed: " + ec.message();
1510 phosphor::logging::log<phosphor::logging::level::ERR>(
1511 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001512 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001513 phosphor::logging::log<phosphor::logging::level::INFO>(
1514 "POH timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001515 return;
1516 }
1517
1518 if (getHostState(powerState) !=
1519 "xyz.openbmc_project.State.Host.HostState.Running")
1520 {
1521 return;
1522 }
1523
1524 conn->async_method_call(
1525 [](boost::system::error_code ec,
1526 const std::variant<uint32_t>& pohCounterProperty) {
1527 if (ec)
1528 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001529 phosphor::logging::log<phosphor::logging::level::INFO>(
1530 "error to get poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001531 return;
1532 }
1533 const uint32_t* pohCounter =
1534 std::get_if<uint32_t>(&pohCounterProperty);
1535 if (pohCounter == nullptr)
1536 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001537 phosphor::logging::log<phosphor::logging::level::INFO>(
1538 "unable to read poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001539 return;
1540 }
1541
1542 conn->async_method_call(
1543 [](boost::system::error_code ec) {
1544 if (ec)
1545 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001546 phosphor::logging::log<
1547 phosphor::logging::level::INFO>(
1548 "failed to set poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001549 }
1550 },
1551 "xyz.openbmc_project.Settings",
1552 "/xyz/openbmc_project/state/chassis0",
1553 "org.freedesktop.DBus.Properties", "Set",
1554 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1555 std::variant<uint32_t>(*pohCounter + 1));
1556 },
1557 "xyz.openbmc_project.Settings",
1558 "/xyz/openbmc_project/state/chassis0",
1559 "org.freedesktop.DBus.Properties", "Get",
1560 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1561
1562 pohCounterTimerStart();
1563 });
1564}
1565
1566static void currentHostStateMonitor()
1567{
Yong Li8d660212019-12-27 10:18:10 +08001568 if (getHostState(powerState) ==
1569 "xyz.openbmc_project.State.Host.HostState.Running")
1570 {
1571 pohCounterTimerStart();
1572 // Clear the restart cause set for the next restart
1573 clearRestartCause();
1574 }
1575 else
1576 {
1577 pohCounterTimer.cancel();
1578 // Set the restart cause set for this restart
1579 setRestartCause();
1580 }
1581
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001582 static auto match = sdbusplus::bus::match::match(
1583 *conn,
1584 "type='signal',member='PropertiesChanged', "
1585 "interface='org.freedesktop.DBus.Properties', "
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001586 "arg0='xyz.openbmc_project.State.Host'",
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001587 [](sdbusplus::message::message& message) {
1588 std::string intfName;
1589 std::map<std::string, std::variant<std::string>> properties;
1590
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001591 try
1592 {
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001593 message.read(intfName, properties);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001594 }
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001595 catch (std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001596 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001597 phosphor::logging::log<phosphor::logging::level::ERR>(
1598 "Unable to read host state");
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001599 return;
1600 }
1601 if (properties.empty())
1602 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001603 phosphor::logging::log<phosphor::logging::level::ERR>(
1604 "ERROR: Empty PropertiesChanged signal received");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001605 return;
1606 }
1607
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001608 // We only want to check for CurrentHostState
1609 if (properties.begin()->first != "CurrentHostState")
1610 {
1611 return;
1612 }
1613 std::string* currentHostState =
1614 std::get_if<std::string>(&(properties.begin()->second));
1615 if (currentHostState == nullptr)
1616 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001617 std::string errMsg =
1618 properties.begin()->first + " property invalid";
1619 phosphor::logging::log<phosphor::logging::level::ERR>(
1620 errMsg.c_str());
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001621 return;
1622 }
1623
1624 if (*currentHostState ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001625 "xyz.openbmc_project.State.Host.HostState.Running")
1626 {
1627 pohCounterTimerStart();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001628 // Clear the restart cause set for the next restart
1629 clearRestartCause();
Yong Li8d660212019-12-27 10:18:10 +08001630 sd_journal_send("MESSAGE=Host system DC power is on",
1631 "PRIORITY=%i", LOG_INFO,
1632 "REDFISH_MESSAGE_ID=%s",
1633 "OpenBMC.0.1.DCPowerOn", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001634 }
1635 else
1636 {
1637 pohCounterTimer.cancel();
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301638 // POST_COMPLETE GPIO event is not working in some platforms
1639 // when power state is changed to OFF. This resulted in
1640 // 'OperatingSystemState' to stay at 'Standby', even though
1641 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1642 // if HostState is trurned to OFF.
1643 osIface->set_property("OperatingSystemState",
1644 std::string("Inactive"));
1645
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001646 // Set the restart cause set for this restart
1647 setRestartCause();
Rashmi RV89f61312020-01-22 15:41:50 +05301648 resetACBootProperty();
Yong Li8d660212019-12-27 10:18:10 +08001649 sd_journal_send("MESSAGE=Host system DC power is off",
1650 "PRIORITY=%i", LOG_INFO,
1651 "REDFISH_MESSAGE_ID=%s",
1652 "OpenBMC.0.1.DCPowerOff", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001653 }
1654 });
1655}
1656
1657static void sioPowerGoodWatchdogTimerStart()
1658{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001659 phosphor::logging::log<phosphor::logging::level::INFO>(
1660 "SIO power good watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001661 sioPowerGoodWatchdogTimer.expires_after(
Priyatharshan P70120512020-09-16 18:47:20 +05301662 std::chrono::milliseconds(TimerMap["sioPowerGoodWatchdogTimeMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001663 sioPowerGoodWatchdogTimer.async_wait(
1664 [](const boost::system::error_code ec) {
1665 if (ec)
1666 {
1667 // operation_aborted is expected if timer is canceled before
1668 // completion.
1669 if (ec != boost::asio::error::operation_aborted)
1670 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001671 std::string errMsg =
1672 "SIO power good watchdog async_wait failed: " +
1673 ec.message();
1674 phosphor::logging::log<phosphor::logging::level::ERR>(
1675 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001676 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001677 phosphor::logging::log<phosphor::logging::level::INFO>(
1678 "SIO power good watchdog timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001679 return;
1680 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001681 phosphor::logging::log<phosphor::logging::level::INFO>(
1682 "SIO power good watchdog timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001683 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1684 });
1685}
1686
1687static void powerStateOn(const Event event)
1688{
1689 logEvent(__FUNCTION__, event);
1690 switch (event)
1691 {
1692 case Event::psPowerOKDeAssert:
1693 setPowerState(PowerState::off);
1694 // DC power is unexpectedly lost, beep
1695 beep(beepPowerFail);
1696 break;
1697 case Event::sioS5Assert:
1698 setPowerState(PowerState::transitionToOff);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001699 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001700 break;
Jason M. Billsfb957332021-01-28 13:18:46 -08001701#if USE_PLT_RST
1702 case Event::pltRstAssert:
1703#else
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001704 case Event::postCompleteDeAssert:
Jason M. Billsfb957332021-01-28 13:18:46 -08001705#endif
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001706 setPowerState(PowerState::checkForWarmReset);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001707 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001708 warmResetCheckTimerStart();
1709 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001710 case Event::powerButtonPressed:
1711 setPowerState(PowerState::gracefulTransitionToOff);
1712 gracefulPowerOffTimerStart();
1713 break;
1714 case Event::powerOffRequest:
1715 setPowerState(PowerState::transitionToOff);
1716 forcePowerOff();
1717 break;
1718 case Event::gracefulPowerOffRequest:
1719 setPowerState(PowerState::gracefulTransitionToOff);
1720 gracefulPowerOffTimerStart();
1721 gracefulPowerOff();
1722 break;
1723 case Event::powerCycleRequest:
1724 setPowerState(PowerState::transitionToCycleOff);
1725 forcePowerOff();
1726 break;
1727 case Event::gracefulPowerCycleRequest:
1728 setPowerState(PowerState::gracefulTransitionToCycleOff);
1729 gracefulPowerOffTimerStart();
1730 gracefulPowerOff();
1731 break;
1732 case Event::resetRequest:
1733 reset();
1734 break;
1735 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001736 phosphor::logging::log<phosphor::logging::level::INFO>(
1737 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001738 break;
1739 }
1740}
1741
1742static void powerStateWaitForPSPowerOK(const Event event)
1743{
1744 logEvent(__FUNCTION__, event);
1745 switch (event)
1746 {
1747 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301748 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001749 // Cancel any GPIO assertions held during the transition
1750 gpioAssertTimer.cancel();
1751 psPowerOKWatchdogTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301752 if (sioEnabled == true)
1753 {
1754 sioPowerGoodWatchdogTimerStart();
1755 setPowerState(PowerState::waitForSIOPowerGood);
1756 }
1757 else
1758 {
1759 setPowerState(PowerState::on);
1760 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001761 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301762 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001763 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001764 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001765 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001766 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001767 case Event::sioPowerGoodAssert:
1768 psPowerOKWatchdogTimer.cancel();
1769 setPowerState(PowerState::on);
1770 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001771 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001772 phosphor::logging::log<phosphor::logging::level::INFO>(
1773 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001774 break;
1775 }
1776}
1777
1778static void powerStateWaitForSIOPowerGood(const Event event)
1779{
1780 logEvent(__FUNCTION__, event);
1781 switch (event)
1782 {
1783 case Event::sioPowerGoodAssert:
1784 sioPowerGoodWatchdogTimer.cancel();
1785 setPowerState(PowerState::on);
1786 break;
1787 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001788 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001789 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001790 break;
1791 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001792 phosphor::logging::log<phosphor::logging::level::INFO>(
1793 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001794 break;
1795 }
1796}
1797
1798static void powerStateOff(const Event event)
1799{
1800 logEvent(__FUNCTION__, event);
1801 switch (event)
1802 {
1803 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301804 {
1805 if (sioEnabled == true)
1806 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001807 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301808 setPowerState(PowerState::waitForSIOPowerGood);
1809 }
1810 else
1811 {
1812 setPowerState(PowerState::on);
1813 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001814 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301815 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001816 case Event::sioS5DeAssert:
1817 setPowerState(PowerState::waitForPSPowerOK);
1818 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001819 case Event::sioPowerGoodAssert:
1820 setPowerState(PowerState::on);
1821 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001822 case Event::powerButtonPressed:
1823 psPowerOKWatchdogTimerStart();
1824 setPowerState(PowerState::waitForPSPowerOK);
1825 break;
1826 case Event::powerOnRequest:
1827 psPowerOKWatchdogTimerStart();
1828 setPowerState(PowerState::waitForPSPowerOK);
1829 powerOn();
1830 break;
1831 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001832 phosphor::logging::log<phosphor::logging::level::INFO>(
1833 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001834 break;
1835 }
1836}
1837
1838static void powerStateTransitionToOff(const Event event)
1839{
1840 logEvent(__FUNCTION__, event);
1841 switch (event)
1842 {
1843 case Event::psPowerOKDeAssert:
1844 // Cancel any GPIO assertions held during the transition
1845 gpioAssertTimer.cancel();
1846 setPowerState(PowerState::off);
1847 break;
1848 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001849 phosphor::logging::log<phosphor::logging::level::INFO>(
1850 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001851 break;
1852 }
1853}
1854
1855static void powerStateGracefulTransitionToOff(const Event event)
1856{
1857 logEvent(__FUNCTION__, event);
1858 switch (event)
1859 {
1860 case Event::psPowerOKDeAssert:
1861 gracefulPowerOffTimer.cancel();
1862 setPowerState(PowerState::off);
1863 break;
1864 case Event::gracefulPowerOffTimerExpired:
1865 setPowerState(PowerState::on);
1866 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001867 case Event::powerOffRequest:
1868 gracefulPowerOffTimer.cancel();
1869 setPowerState(PowerState::transitionToOff);
1870 forcePowerOff();
1871 break;
1872 case Event::powerCycleRequest:
1873 gracefulPowerOffTimer.cancel();
1874 setPowerState(PowerState::transitionToCycleOff);
1875 forcePowerOff();
1876 break;
1877 case Event::resetRequest:
1878 gracefulPowerOffTimer.cancel();
1879 setPowerState(PowerState::on);
1880 reset();
1881 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001882 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001883 phosphor::logging::log<phosphor::logging::level::INFO>(
1884 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001885 break;
1886 }
1887}
1888
1889static void powerStateCycleOff(const Event event)
1890{
1891 logEvent(__FUNCTION__, event);
1892 switch (event)
1893 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001894 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301895 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001896 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301897 if (sioEnabled == true)
1898 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001899 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301900 setPowerState(PowerState::waitForSIOPowerGood);
1901 }
1902 else
1903 {
1904 setPowerState(PowerState::on);
1905 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001906 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301907 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001908 case Event::sioS5DeAssert:
1909 powerCycleTimer.cancel();
1910 setPowerState(PowerState::waitForPSPowerOK);
1911 break;
1912 case Event::powerButtonPressed:
1913 powerCycleTimer.cancel();
1914 psPowerOKWatchdogTimerStart();
1915 setPowerState(PowerState::waitForPSPowerOK);
1916 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001917 case Event::powerCycleTimerExpired:
1918 psPowerOKWatchdogTimerStart();
1919 setPowerState(PowerState::waitForPSPowerOK);
1920 powerOn();
1921 break;
1922 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001923 phosphor::logging::log<phosphor::logging::level::INFO>(
1924 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001925 break;
1926 }
1927}
1928
1929static void powerStateTransitionToCycleOff(const Event event)
1930{
1931 logEvent(__FUNCTION__, event);
1932 switch (event)
1933 {
1934 case Event::psPowerOKDeAssert:
1935 // Cancel any GPIO assertions held during the transition
1936 gpioAssertTimer.cancel();
1937 setPowerState(PowerState::cycleOff);
1938 powerCycleTimerStart();
1939 break;
1940 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001941 phosphor::logging::log<phosphor::logging::level::INFO>(
1942 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001943 break;
1944 }
1945}
1946
1947static void powerStateGracefulTransitionToCycleOff(const Event event)
1948{
1949 logEvent(__FUNCTION__, event);
1950 switch (event)
1951 {
1952 case Event::psPowerOKDeAssert:
1953 gracefulPowerOffTimer.cancel();
1954 setPowerState(PowerState::cycleOff);
1955 powerCycleTimerStart();
1956 break;
1957 case Event::gracefulPowerOffTimerExpired:
1958 setPowerState(PowerState::on);
1959 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001960 case Event::powerOffRequest:
1961 gracefulPowerOffTimer.cancel();
1962 setPowerState(PowerState::transitionToOff);
1963 forcePowerOff();
1964 break;
1965 case Event::powerCycleRequest:
1966 gracefulPowerOffTimer.cancel();
1967 setPowerState(PowerState::transitionToCycleOff);
1968 forcePowerOff();
1969 break;
1970 case Event::resetRequest:
1971 gracefulPowerOffTimer.cancel();
1972 setPowerState(PowerState::on);
1973 reset();
1974 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001975 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001976 phosphor::logging::log<phosphor::logging::level::INFO>(
1977 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001978 break;
1979 }
1980}
1981
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001982static void powerStateCheckForWarmReset(const Event event)
1983{
1984 logEvent(__FUNCTION__, event);
1985 switch (event)
1986 {
1987 case Event::sioS5Assert:
1988 warmResetCheckTimer.cancel();
1989 setPowerState(PowerState::transitionToOff);
1990 break;
1991 case Event::warmResetDetected:
1992 setPowerState(PowerState::on);
1993 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001994 case Event::psPowerOKDeAssert:
1995 warmResetCheckTimer.cancel();
1996 setPowerState(PowerState::off);
1997 // DC power is unexpectedly lost, beep
1998 beep(beepPowerFail);
1999 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002000 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07002001 phosphor::logging::log<phosphor::logging::level::INFO>(
2002 "No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002003 break;
2004 }
2005}
2006
Zev Weiss584aa132021-09-02 19:21:52 -05002007static void psPowerOKHandler(bool state)
2008{
2009 Event powerControlEvent =
2010 state ? Event::psPowerOKAssert : Event::psPowerOKDeAssert;
2011 sendPowerControlEvent(powerControlEvent);
2012}
2013
Zev Weiss584aa132021-09-02 19:21:52 -05002014static void sioPowerGoodHandler(bool state)
2015{
2016 Event powerControlEvent =
2017 state ? Event::sioPowerGoodAssert : Event::sioPowerGoodDeAssert;
2018 sendPowerControlEvent(powerControlEvent);
2019}
2020
Zev Weiss584aa132021-09-02 19:21:52 -05002021static void sioOnControlHandler(bool state)
2022{
2023 std::string logMsg =
2024 "SIO_ONCONTROL value changed: " + std::to_string(state);
2025 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
2026}
2027
Zev Weiss584aa132021-09-02 19:21:52 -05002028static void sioS5Handler(bool state)
2029{
2030 Event powerControlEvent = state ? Event::sioS5DeAssert : Event::sioS5Assert;
2031 sendPowerControlEvent(powerControlEvent);
2032}
2033
Zev Weiss584aa132021-09-02 19:21:52 -05002034static void powerButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002035{
Zev Weiss584aa132021-09-02 19:21:52 -05002036 powerButtonIface->set_property("ButtonPressed", !state);
2037 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002038 {
2039 powerButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002040 if (!powerButtonMask)
2041 {
2042 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002043 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002044 }
2045 else
2046 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002047 phosphor::logging::log<phosphor::logging::level::INFO>(
2048 "power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002049 }
2050 }
Zev Weiss584aa132021-09-02 19:21:52 -05002051}
2052
Zev Weiss584aa132021-09-02 19:21:52 -05002053static void resetButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002054{
Zev Weiss584aa132021-09-02 19:21:52 -05002055 resetButtonIface->set_property("ButtonPressed", !state);
2056 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002057 {
2058 resetButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002059 if (!resetButtonMask)
2060 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002061 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002062 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002063 }
2064 else
2065 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002066 phosphor::logging::log<phosphor::logging::level::INFO>(
2067 "reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002068 }
2069 }
Zev Weiss584aa132021-09-02 19:21:52 -05002070}
2071
Vijay Khemka04175c22020-10-09 14:28:11 -07002072#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002073static constexpr auto systemdBusname = "org.freedesktop.systemd1";
2074static constexpr auto systemdPath = "/org/freedesktop/systemd1";
2075static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
2076static constexpr auto systemTargetName = "chassis-system-reset.target";
2077
2078void systemReset()
2079{
2080 conn->async_method_call(
2081 [](boost::system::error_code ec) {
2082 if (ec)
2083 {
2084 phosphor::logging::log<phosphor::logging::level::ERR>(
2085 "Failed to call chassis system reset",
2086 phosphor::logging::entry("ERR=%s", ec.message().c_str()));
2087 }
2088 },
2089 systemdBusname, systemdPath, systemdInterface, "StartUnit",
2090 systemTargetName, "replace");
2091}
Vijay Khemka04175c22020-10-09 14:28:11 -07002092#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002093
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002094static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002095{
2096 conn->async_method_call(
2097 [](boost::system::error_code ec) {
2098 if (ec)
2099 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002100 phosphor::logging::log<phosphor::logging::level::INFO>(
2101 "failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002102 }
2103 },
Chen Yugang303bd582019-11-01 08:45:06 +08002104 "xyz.openbmc_project.Settings",
2105 "/xyz/openbmc_project/Chassis/Control/NMISource",
2106 "org.freedesktop.DBus.Properties", "Set",
2107 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
2108 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002109}
2110
2111static void nmiReset(void)
2112{
2113 static constexpr const uint8_t value = 1;
2114 const static constexpr int nmiOutPulseTimeMs = 200;
2115
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002116 phosphor::logging::log<phosphor::logging::level::INFO>("NMI out action");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002117 nmiOutLine.set_value(value);
Priyatharshan P70120512020-09-16 18:47:20 +05302118 std::string logMsg =
2119 nmiOutConfig.lineName + " set to " + std::to_string(value);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002120 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002121 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2122 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2123 // restore the NMI_OUT GPIO line back to the opposite value
2124 nmiOutLine.set_value(!value);
Priyatharshan P70120512020-09-16 18:47:20 +05302125 std::string logMsg = nmiOutConfig.lineName + " released";
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002126 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002127 if (ec)
2128 {
2129 // operation_aborted is expected if timer is canceled before
2130 // completion.
2131 if (ec != boost::asio::error::operation_aborted)
2132 {
Priyatharshan P70120512020-09-16 18:47:20 +05302133 std::string errMsg = nmiOutConfig.lineName +
2134 " async_wait failed: " + ec.message();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002135 phosphor::logging::log<phosphor::logging::level::ERR>(
2136 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002137 }
2138 }
2139 });
2140 // log to redfish
2141 nmiDiagIntLog();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002142 phosphor::logging::log<phosphor::logging::level::INFO>(
2143 "NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002144 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002145 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002146}
2147
2148static void nmiSourcePropertyMonitor(void)
2149{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002150 phosphor::logging::log<phosphor::logging::level::INFO>(
2151 "NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002152
2153 static std::unique_ptr<sdbusplus::bus::match::match> nmiSourceMatch =
2154 std::make_unique<sdbusplus::bus::match::match>(
2155 *conn,
2156 "type='signal',interface='org.freedesktop.DBus.Properties',"
Chen Yugang303bd582019-11-01 08:45:06 +08002157 "member='PropertiesChanged',arg0namespace='xyz.openbmc_project."
2158 "Chassis.Control."
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002159 "NMISource'",
2160 [](sdbusplus::message::message& msg) {
2161 std::string interfaceName;
2162 boost::container::flat_map<std::string,
2163 std::variant<bool, std::string>>
2164 propertiesChanged;
2165 std::string state;
2166 bool value = true;
2167 try
2168 {
2169 msg.read(interfaceName, propertiesChanged);
2170 if (propertiesChanged.begin()->first == "Enabled")
2171 {
2172 value =
2173 std::get<bool>(propertiesChanged.begin()->second);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002174 std::string logMsg =
2175 " NMI Enabled propertiesChanged value: " +
2176 std::to_string(value);
2177 phosphor::logging::log<phosphor::logging::level::INFO>(
2178 logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002179 nmiEnabled = value;
2180 if (nmiEnabled)
2181 {
2182 nmiReset();
2183 }
2184 }
2185 }
2186 catch (std::exception& e)
2187 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002188 phosphor::logging::log<phosphor::logging::level::ERR>(
2189 "Unable to read NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002190 return;
2191 }
2192 });
2193}
2194
2195static void setNmiSource()
2196{
2197 conn->async_method_call(
2198 [](boost::system::error_code ec) {
2199 if (ec)
2200 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002201 phosphor::logging::log<phosphor::logging::level::ERR>(
2202 "failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002203 }
2204 },
Chen Yugang303bd582019-11-01 08:45:06 +08002205 "xyz.openbmc_project.Settings",
2206 "/xyz/openbmc_project/Chassis/Control/NMISource",
2207 "org.freedesktop.DBus.Properties", "Set",
2208 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
2209 std::variant<std::string>{"xyz.openbmc_project.Chassis.Control."
2210 "NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002211 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002212 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002213}
2214
Zev Weiss584aa132021-09-02 19:21:52 -05002215static void nmiButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002216{
Zev Weiss584aa132021-09-02 19:21:52 -05002217 nmiButtonIface->set_property("ButtonPressed", !state);
2218 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002219 {
2220 nmiButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002221 if (nmiButtonMasked)
2222 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002223 phosphor::logging::log<phosphor::logging::level::INFO>(
2224 "NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002225 }
2226 else
2227 {
2228 setNmiSource();
2229 }
2230 }
Zev Weiss584aa132021-09-02 19:21:52 -05002231}
2232
Zev Weiss584aa132021-09-02 19:21:52 -05002233static void idButtonHandler(bool state)
2234{
2235 idButtonIface->set_property("ButtonPressed", !state);
2236}
2237
Jason M. Billsfb957332021-01-28 13:18:46 -08002238static void pltRstHandler(bool pltRst)
2239{
2240 if (pltRst)
2241 {
2242 sendPowerControlEvent(Event::pltRstDeAssert);
2243 }
2244 else
2245 {
2246 sendPowerControlEvent(Event::pltRstAssert);
2247 }
2248}
2249
2250static void hostMiscHandler(sdbusplus::message::message& msg)
2251{
2252 std::string interfaceName;
2253 boost::container::flat_map<std::string, std::variant<bool>>
2254 propertiesChanged;
2255 bool pltRst;
2256 try
2257 {
2258 msg.read(interfaceName, propertiesChanged);
2259 }
2260 catch (std::exception& e)
2261 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002262 phosphor::logging::log<phosphor::logging::level::ERR>(
2263 "Unable to read Host Misc status");
Jason M. Billsfb957332021-01-28 13:18:46 -08002264 return;
2265 }
2266 if (propertiesChanged.empty())
2267 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002268 phosphor::logging::log<phosphor::logging::level::ERR>(
2269 "ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002270 return;
2271 }
2272
2273 for (auto& [property, value] : propertiesChanged)
2274 {
2275 if (property == "ESpiPlatformReset")
2276 {
2277 bool* pltRst = std::get_if<bool>(&value);
2278 if (pltRst == nullptr)
2279 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002280 std::string errMsg = property + " property invalid";
2281 phosphor::logging::log<phosphor::logging::level::ERR>(
2282 errMsg.c_str());
Jason M. Billsfb957332021-01-28 13:18:46 -08002283 return;
2284 }
2285 pltRstHandler(*pltRst);
2286 }
2287 }
2288}
2289
Zev Weiss584aa132021-09-02 19:21:52 -05002290static void postCompleteHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002291{
Zev Weiss584aa132021-09-02 19:21:52 -05002292 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002293 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002294 sendPowerControlEvent(Event::postCompleteAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002295 osIface->set_property("OperatingSystemState", std::string("Standby"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002296 }
2297 else
2298 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002299 sendPowerControlEvent(Event::postCompleteDeAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002300 osIface->set_property("OperatingSystemState", std::string("Inactive"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002301 }
Zev Weiss584aa132021-09-02 19:21:52 -05002302}
2303
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302304static int loadConfigValues()
2305{
2306 const std::string configFilePath =
2307 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2308 ".json";
2309 std::ifstream configFile(configFilePath.c_str());
2310 if (!configFile.is_open())
2311 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002312 phosphor::logging::log<phosphor::logging::level::ERR>(
2313 "loadConfigValues : Cannot open config path");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302314 return -1;
2315 }
Zev Weiss1aa08b22021-09-15 17:06:20 -05002316 auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302317
Priyatharshan P70120512020-09-16 18:47:20 +05302318 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302319 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002320 phosphor::logging::log<phosphor::logging::level::ERR>(
2321 "Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302322 return -1;
2323 }
Priyatharshan P70120512020-09-16 18:47:20 +05302324 auto gpios = jsonData["gpio_configs"];
2325 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302326
Priyatharshan P70120512020-09-16 18:47:20 +05302327 ConfigData* tempGpioData;
2328
2329 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302330 {
Priyatharshan P70120512020-09-16 18:47:20 +05302331 if (!gpioConfig.contains("Name"))
2332 {
2333 phosphor::logging::log<phosphor::logging::level::ERR>(
2334 "The 'Name' field must be defined in Json file");
2335 return -1;
2336 }
2337
2338 // Iterate through the powersignal map to check if the gpio json config
2339 // entry is valid
2340 std::string gpioName = gpioConfig["Name"];
2341 auto signalMapIter = powerSignalMap.find(gpioName);
2342 if (signalMapIter == powerSignalMap.end())
2343 {
2344 std::string errMsg = "Undefined Name : " + gpioName;
2345 phosphor::logging::log<phosphor::logging::level::ERR>(
2346 errMsg.c_str());
2347 return -1;
2348 }
2349
2350 // assign the power signal name to the corresponding structure reference
2351 // from map then fillup the structure with coressponding json config
2352 // value
2353 tempGpioData = signalMapIter->second;
2354 tempGpioData->name = gpioName;
2355
2356 if (!gpioConfig.contains("Type"))
2357 {
2358 phosphor::logging::log<phosphor::logging::level::ERR>(
2359 "The \'Type\' field must be defined in Json file");
2360 return -1;
2361 }
2362
2363 std::string signalType = gpioConfig["Type"];
2364 if (signalType == "GPIO")
2365 {
2366 tempGpioData->type = ConfigType::GPIO;
2367 }
2368 else if (signalType == "DBUS")
2369 {
2370 tempGpioData->type = ConfigType::DBUS;
2371 }
2372 else
2373 {
2374 std::string errMsg = "Undefined Type : " + signalType;
2375 phosphor::logging::log<phosphor::logging::level::ERR>(
2376 errMsg.c_str());
2377 return -1;
2378 }
2379
2380 if (tempGpioData->type == ConfigType::GPIO)
2381 {
2382 if (gpioConfig.contains("LineName"))
2383 {
2384 tempGpioData->lineName = gpioConfig["LineName"];
2385 }
2386 else
2387 {
2388 phosphor::logging::log<phosphor::logging::level::ERR>(
2389 "The \'LineName\' field must be defined for GPIO "
2390 "configuration");
2391 return -1;
2392 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002393 if (gpioConfig.contains("Polarity"))
2394 {
2395 std::string polarity = gpioConfig["Polarity"];
2396 if (polarity == "ActiveLow")
2397 {
2398 tempGpioData->polarity = false;
2399 }
2400 else if (polarity == "ActiveHigh")
2401 {
2402 tempGpioData->polarity = true;
2403 }
2404 else
2405 {
2406 std::string errMsg =
2407 "Polarity defined but not properly setup. Please "
2408 "only ActiveHigh or ActiveLow. Currently set to " +
2409 polarity;
2410 phosphor::logging::log<phosphor::logging::level::ERR>(
2411 errMsg.c_str());
2412 return -1;
2413 }
2414 }
2415 else
2416 {
2417 std::string errMsg =
2418 "Polarity field not found for " + tempGpioData->lineName;
2419 phosphor::logging::log<phosphor::logging::level::ERR>(
2420 errMsg.c_str());
2421 return -1;
2422 }
Priyatharshan P70120512020-09-16 18:47:20 +05302423 }
2424 else
2425 {
2426 // if dbus based gpio config is defined read and update the dbus
2427 // params corresponding to the gpio config instance
2428 for (auto& [key, dbusParamName] : dbusParams)
2429 {
2430 if (!gpios.contains(dbusParamName))
2431 {
2432 std::string errMsg =
2433 "The " + dbusParamName +
2434 "field must be defined for Dbus configuration ";
2435 phosphor::logging::log<phosphor::logging::level::ERR>(
2436 errMsg.c_str());
2437 return -1;
2438 }
2439 }
2440 tempGpioData->dbusName = gpios[dbusParams[DbusConfigType::name]];
2441 tempGpioData->path = gpios[dbusParams[DbusConfigType::path]];
2442 tempGpioData->interface =
2443 gpios[dbusParams[DbusConfigType::interface]];
2444 tempGpioData->lineName =
2445 gpios[dbusParams[DbusConfigType::property]];
2446 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302447 }
2448
Priyatharshan P70120512020-09-16 18:47:20 +05302449 // read and store the timer values from json config to Timer Map
2450 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302451 {
Priyatharshan P70120512020-09-16 18:47:20 +05302452 if (timers.contains(key.c_str()))
2453 {
2454 timerValue = timers[key.c_str()];
2455 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302456 }
2457
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302458 return 0;
2459}
Zev Weissa8f116a2021-09-01 21:08:30 -05002460
2461static bool getDbusMsgGPIOState(sdbusplus::message::message& msg,
2462 const std::string& lineName, bool& value)
2463{
2464 std::string thresholdInterface;
2465 std::string event;
2466 boost::container::flat_map<std::string, std::variant<bool>>
2467 propertiesChanged;
2468 try
2469 {
2470 msg.read(thresholdInterface, propertiesChanged);
2471 if (propertiesChanged.empty())
2472 {
2473 return false;
2474 }
2475
2476 event = propertiesChanged.begin()->first;
2477 if (event.empty() || event != lineName)
2478 {
2479 return false;
2480 }
2481
2482 value = std::get<bool>(propertiesChanged.begin()->second);
2483 return true;
2484 }
2485 catch (std::exception& e)
2486 {
2487 std::string logmsg =
2488 "exception while reading dbus property: " + lineName;
2489 phosphor::logging::log<phosphor::logging::level::ERR>(logmsg.c_str());
2490 return false;
2491 }
2492}
2493
2494static sdbusplus::bus::match::match
2495 dbusGPIOMatcher(const ConfigData& cfg, std::function<void(bool)> onMatch)
2496{
2497 auto pulseEventMatcherCallback =
2498 [&cfg, onMatch](sdbusplus::message::message& msg) {
2499 bool value = false;
2500 if (!getDbusMsgGPIOState(msg, cfg.lineName, value))
2501 {
2502 return;
2503 }
2504 onMatch(value);
2505 };
2506
2507 return sdbusplus::bus::match::match(
2508 static_cast<sdbusplus::bus::bus&>(*conn),
2509 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2510 "PropertiesChanged',arg0='" +
2511 cfg.dbusName + "'",
2512 std::move(pulseEventMatcherCallback));
2513}
2514
Priyatharshan P70120512020-09-16 18:47:20 +05302515int getProperty(ConfigData& configData)
2516{
2517 auto method = conn->new_method_call(
2518 configData.dbusName.c_str(), configData.path.c_str(),
2519 "org.freedesktop.DBus.Properties", "Get");
2520 method.append(configData.interface.c_str(), configData.lineName.c_str());
2521
2522 auto reply = conn->call(method);
2523 if (reply.is_method_error())
2524 {
2525 phosphor::logging::log<phosphor::logging::level::ERR>(
2526 "Error reading from Bus");
2527 return -1;
2528 }
2529 std::variant<int> resp;
2530 reply.read(resp);
2531 auto respValue = std::get_if<int>(&resp);
2532 if (!respValue)
2533 {
2534 phosphor::logging::log<phosphor::logging::level::ERR>(
2535 "Error reading response");
2536 return -1;
2537 }
2538 return (*respValue);
2539}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002540} // namespace power_control
2541
2542int main(int argc, char* argv[])
2543{
Lei YU92caa4c2021-02-23 16:59:25 +08002544 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05302545
2546 if (argc > 1)
2547 {
2548 node = argv[1];
2549 }
2550 std::string infoMsg =
2551 "Start Chassis power control service for host : " + node;
2552 phosphor::logging::log<phosphor::logging::level::INFO>(infoMsg.c_str());
2553
Lei YU92caa4c2021-02-23 16:59:25 +08002554 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002555
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302556 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08002557 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302558 {
Lei YU92caa4c2021-02-23 16:59:25 +08002559 std::string errMsg = "Host" + node + ": " + "Error in Parsing...";
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002560 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302561 }
Naveen Mosesec972d82021-07-16 21:19:23 +05302562 /* Currently for single host based systems additional busname is added
2563 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
2564 Going forward for single hosts the old bus name without zero numbering
2565 will be removed when all other applications adapted to the
2566 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
2567
2568 if (node == "0")
2569 {
2570 // Request all the dbus names
2571 conn->request_name(hostDbusName.c_str());
2572 conn->request_name(chassisDbusName.c_str());
2573 conn->request_name(osDbusName.c_str());
2574 conn->request_name(buttonDbusName.c_str());
2575 conn->request_name(nmiDbusName.c_str());
2576 conn->request_name(rstCauseDbusName.c_str());
2577 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302578
Zev Weissc4005bd2021-09-01 22:30:23 -05002579 hostDbusName += node;
2580 chassisDbusName += node;
2581 osDbusName += node;
2582 buttonDbusName += node;
2583 nmiDbusName += node;
2584 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002585
Priyatharshan P70120512020-09-16 18:47:20 +05302586 // Request all the dbus names
2587 conn->request_name(hostDbusName.c_str());
2588 conn->request_name(chassisDbusName.c_str());
2589 conn->request_name(osDbusName.c_str());
2590 conn->request_name(buttonDbusName.c_str());
2591 conn->request_name(nmiDbusName.c_str());
2592 conn->request_name(rstCauseDbusName.c_str());
2593
2594 if (sioPwrGoodConfig.lineName.empty() ||
2595 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05302596 {
Lei YU92caa4c2021-02-23 16:59:25 +08002597 sioEnabled = false;
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002598 phosphor::logging::log<phosphor::logging::level::INFO>(
2599 "SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05302600 }
2601
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002602 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302603 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002604 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002605 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302606 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302607 {
2608 return -1;
2609 }
2610 }
Priyatharshan P70120512020-09-16 18:47:20 +05302611 else if (powerOkConfig.type == ConfigType::DBUS)
2612 {
2613
2614 static sdbusplus::bus::match::match powerOkEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002615 power_control::dbusGPIOMatcher(powerOkConfig, psPowerOKHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302616 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302617 else
2618 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002619 phosphor::logging::log<phosphor::logging::level::ERR>(
2620 "PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002621 return -1;
2622 }
2623
Lei YU92caa4c2021-02-23 16:59:25 +08002624 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002625 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05302626 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302627 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302628 {
Priyatharshan P70120512020-09-16 18:47:20 +05302629 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002630 sioPowerGoodHandler, sioPowerGoodLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302631 sioPowerGoodEvent))
2632 {
2633 return -1;
2634 }
2635 }
2636 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
2637 {
2638 static sdbusplus::bus::match::match sioPwrGoodEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002639 power_control::dbusGPIOMatcher(sioPwrGoodConfig,
2640 sioPowerGoodHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302641 }
2642 else
2643 {
2644 phosphor::logging::log<phosphor::logging::level::ERR>(
2645 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302646 return -1;
2647 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002648
Priyatharshan P19c47a32020-08-12 18:16:43 +05302649 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302650 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302651 {
Priyatharshan P70120512020-09-16 18:47:20 +05302652 if (!requestGPIOEvents(sioOnControlConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002653 sioOnControlHandler, sioOnControlLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302654 sioOnControlEvent))
2655 {
2656 return -1;
2657 }
2658 }
2659 else if (sioOnControlConfig.type == ConfigType::DBUS)
2660 {
2661 static sdbusplus::bus::match::match sioOnControlEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002662 power_control::dbusGPIOMatcher(sioOnControlConfig,
2663 sioOnControlHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302664 }
2665 else
2666 {
2667 phosphor::logging::log<phosphor::logging::level::ERR>(
2668 "sioOnControl name should be configured from json"
2669 "config file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302670 return -1;
2671 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002672
Priyatharshan P19c47a32020-08-12 18:16:43 +05302673 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302674 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302675 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002676 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
Priyatharshan P70120512020-09-16 18:47:20 +05302677 sioS5Line, sioS5Event))
2678 {
2679 return -1;
2680 }
2681 }
2682 else if (sioS5Config.type == ConfigType::DBUS)
2683 {
2684 static sdbusplus::bus::match::match sioS5EventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002685 power_control::dbusGPIOMatcher(sioS5Config, sioS5Handler);
Priyatharshan P70120512020-09-16 18:47:20 +05302686 }
2687 else
2688 {
2689 phosphor::logging::log<phosphor::logging::level::ERR>(
2690 "sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302691 return -1;
2692 }
2693 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002694
2695 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302696 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002697 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002698 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
2699 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302700 {
2701 return -1;
2702 }
2703 }
Priyatharshan P70120512020-09-16 18:47:20 +05302704 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302705 {
Priyatharshan P70120512020-09-16 18:47:20 +05302706 static sdbusplus::bus::match::match powerButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002707 power_control::dbusGPIOMatcher(powerButtonConfig,
2708 powerButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002709 }
2710
2711 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302712 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002713 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002714 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
2715 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302716 {
2717 return -1;
2718 }
2719 }
Priyatharshan P70120512020-09-16 18:47:20 +05302720 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302721 {
Priyatharshan P70120512020-09-16 18:47:20 +05302722 static sdbusplus::bus::match::match resetButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002723 power_control::dbusGPIOMatcher(resetButtonConfig,
2724 resetButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002725 }
2726
2727 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302728 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302729 {
Priyatharshan P70120512020-09-16 18:47:20 +05302730 if (!nmiButtonConfig.lineName.empty())
2731 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002732 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302733 nmiButtonLine, nmiButtonEvent);
2734 }
2735 }
2736 else if (nmiButtonConfig.type == ConfigType::DBUS)
2737 {
2738 static sdbusplus::bus::match::match nmiButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002739 power_control::dbusGPIOMatcher(nmiButtonConfig, nmiButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302740 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002741
2742 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302743 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302744 {
Priyatharshan P70120512020-09-16 18:47:20 +05302745 if (!idButtonConfig.lineName.empty())
2746 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002747 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302748 idButtonLine, idButtonEvent);
2749 }
2750 }
2751 else if (idButtonConfig.type == ConfigType::DBUS)
2752 {
2753 static sdbusplus::bus::match::match idButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002754 power_control::dbusGPIOMatcher(idButtonConfig, idButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302755 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002756
Jason M. Billsfb957332021-01-28 13:18:46 -08002757#ifdef USE_PLT_RST
2758 sdbusplus::bus::match::match pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08002759 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08002760 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2761 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08002762 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08002763#endif
2764
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002765 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302766 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002767 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002768 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
2769 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302770 {
2771 return -1;
2772 }
2773 }
Priyatharshan P70120512020-09-16 18:47:20 +05302774 else if (postCompleteConfig.type == ConfigType::DBUS)
2775 {
2776 static sdbusplus::bus::match::match postCompleteEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002777 power_control::dbusGPIOMatcher(postCompleteConfig,
2778 postCompleteHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302779 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302780 else
2781 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002782 phosphor::logging::log<phosphor::logging::level::ERR>(
2783 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002784 return -1;
2785 }
2786
2787 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05302788 if (!nmiOutConfig.lineName.empty())
2789 {
2790 setGPIOOutput(nmiOutConfig.lineName, 0, nmiOutLine);
2791 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002792
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002793 // Initialize POWER_OUT and RESET_OUT GPIO.
2794 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05302795 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002796 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002797 if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
2798 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302799 {
2800 return -1;
2801 }
2802 }
2803 else
2804 {
2805 phosphor::logging::log<phosphor::logging::level::ERR>(
2806 "powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002807 return -1;
2808 }
2809
Priyatharshan P70120512020-09-16 18:47:20 +05302810 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002811 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002812 if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
2813 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302814 {
2815 return -1;
2816 }
2817 }
2818 else
2819 {
2820 phosphor::logging::log<phosphor::logging::level::ERR>(
2821 "ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002822 return -1;
2823 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002824 // Release line
2825 line.reset();
2826
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002827 // Initialize the power state
Lei YU92caa4c2021-02-23 16:59:25 +08002828 powerState = PowerState::off;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002829 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05302830
2831 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002832 {
Jean-Marie Verdun61b4a5b2021-09-19 08:53:28 -04002833 if (psPowerOKLine.get_value() > 0 ||
2834 sioPowerGoodLine.get_value() == sioPwrGoodConfig.polarity)
Priyatharshan P70120512020-09-16 18:47:20 +05302835 {
2836 powerState = PowerState::on;
2837 }
2838 }
2839 else
2840 {
2841 if (getProperty(powerOkConfig))
2842 {
2843 powerState = PowerState::on;
2844 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002845 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002846 // Initialize the power state storage
Lei YU92caa4c2021-02-23 16:59:25 +08002847 if (initializePowerStateStorage() < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002848 {
2849 return -1;
2850 }
2851
2852 // Check if we need to start the Power Restore policy
Lei YU92caa4c2021-02-23 16:59:25 +08002853 powerRestorePolicyCheck();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002854
Lei YU92caa4c2021-02-23 16:59:25 +08002855 if (nmiOutLine)
2856 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002857
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002858 phosphor::logging::log<phosphor::logging::level::INFO>(
2859 "Initializing power state. ");
Lei YU92caa4c2021-02-23 16:59:25 +08002860 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002861
2862 // Power Control Service
2863 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002864 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002865
2866 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05302867 hostIface =
2868 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
2869 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002870 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08002871 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002872 "RequestedHostTransition",
2873 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2874 [](const std::string& requested, std::string& resp) {
2875 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2876 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002877 // if power button is masked, ignore this
2878 if (!powerButtonMask)
2879 {
2880 sendPowerControlEvent(Event::gracefulPowerOffRequest);
2881 addRestartCause(RestartCause::command);
2882 }
2883 else
2884 {
2885 phosphor::logging::log<phosphor::logging::level::INFO>(
2886 "Power Button Masked.");
2887 throw std::invalid_argument("Transition Request Masked");
2888 return 0;
2889 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002890 }
2891 else if (requested ==
2892 "xyz.openbmc_project.State.Host.Transition.On")
2893 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002894 // if power button is masked, ignore this
2895 if (!powerButtonMask)
2896 {
2897 sendPowerControlEvent(Event::powerOnRequest);
2898 addRestartCause(RestartCause::command);
2899 }
2900 else
2901 {
2902 phosphor::logging::log<phosphor::logging::level::INFO>(
2903 "Power Button Masked.");
2904 throw std::invalid_argument("Transition Request Masked");
2905 return 0;
2906 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002907 }
2908 else if (requested ==
2909 "xyz.openbmc_project.State.Host.Transition.Reboot")
2910 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002911 // if power button is masked, ignore this
2912 if (!powerButtonMask)
2913 {
2914 sendPowerControlEvent(Event::powerCycleRequest);
2915 addRestartCause(RestartCause::command);
2916 }
2917 else
2918 {
2919 phosphor::logging::log<phosphor::logging::level::INFO>(
2920 "Power Button Masked.");
2921 throw std::invalid_argument("Transition Request Masked");
2922 return 0;
2923 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002924 }
2925 else if (requested == "xyz.openbmc_project.State.Host.Transition."
2926 "GracefulWarmReboot")
2927 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002928 // if reset button is masked, ignore this
2929 if (!resetButtonMask)
2930 {
2931 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
2932 addRestartCause(RestartCause::command);
2933 }
2934 else
2935 {
2936 phosphor::logging::log<phosphor::logging::level::INFO>(
2937 "Reset Button Masked.");
2938 throw std::invalid_argument("Transition Request Masked");
2939 return 0;
2940 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002941 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002942 else if (requested == "xyz.openbmc_project.State.Host.Transition."
2943 "ForceWarmReboot")
2944 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002945 // if reset button is masked, ignore this
2946 if (!resetButtonMask)
2947 {
2948 sendPowerControlEvent(Event::resetRequest);
2949 addRestartCause(RestartCause::command);
2950 }
2951 else
2952 {
2953 phosphor::logging::log<phosphor::logging::level::INFO>(
2954 "Reset Button Masked.");
2955 throw std::invalid_argument("Transition Request Masked");
2956 return 0;
2957 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002958 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002959 else
2960 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002961 phosphor::logging::log<phosphor::logging::level::ERR>(
2962 "Unrecognized host state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002963 throw std::invalid_argument("Unrecognized Transition Request");
2964 return 0;
2965 }
2966 resp = requested;
2967 return 1;
2968 });
Lei YU92caa4c2021-02-23 16:59:25 +08002969 hostIface->register_property("CurrentHostState",
2970 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002971
Lei YU92caa4c2021-02-23 16:59:25 +08002972 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002973
2974 // Chassis Control Service
2975 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002976 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002977
2978 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002979 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05302980 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002981 "xyz.openbmc_project.State.Chassis");
2982
Lei YU92caa4c2021-02-23 16:59:25 +08002983 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002984 "RequestedPowerTransition",
2985 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
2986 [](const std::string& requested, std::string& resp) {
2987 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
2988 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002989 // if power button is masked, ignore this
2990 if (!powerButtonMask)
2991 {
2992 sendPowerControlEvent(Event::powerOffRequest);
2993 addRestartCause(RestartCause::command);
2994 }
2995 else
2996 {
2997 phosphor::logging::log<phosphor::logging::level::INFO>(
2998 "Power Button Masked.");
2999 throw std::invalid_argument("Transition Request Masked");
3000 return 0;
3001 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003002 }
3003 else if (requested ==
3004 "xyz.openbmc_project.State.Chassis.Transition.On")
3005 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003006 // if power button is masked, ignore this
3007 if (!powerButtonMask)
3008 {
3009 sendPowerControlEvent(Event::powerOnRequest);
3010 addRestartCause(RestartCause::command);
3011 }
3012 else
3013 {
3014 phosphor::logging::log<phosphor::logging::level::INFO>(
3015 "Power Button Masked.");
3016 throw std::invalid_argument("Transition Request Masked");
3017 return 0;
3018 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003019 }
3020 else if (requested ==
3021 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3022 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003023 // if power button is masked, ignore this
3024 if (!powerButtonMask)
3025 {
3026 sendPowerControlEvent(Event::powerCycleRequest);
3027 addRestartCause(RestartCause::command);
3028 }
3029 else
3030 {
3031 phosphor::logging::log<phosphor::logging::level::INFO>(
3032 "Power Button Masked.");
3033 throw std::invalid_argument("Transition Request Masked");
3034 return 0;
3035 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003036 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003037 else
3038 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003039 phosphor::logging::log<phosphor::logging::level::ERR>(
3040 "Unrecognized chassis state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003041 throw std::invalid_argument("Unrecognized Transition Request");
3042 return 0;
3043 }
3044 resp = requested;
3045 return 1;
3046 });
Lei YU92caa4c2021-02-23 16:59:25 +08003047 chassisIface->register_property("CurrentPowerState",
3048 std::string(getChassisState(powerState)));
3049 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003050
Lei YU92caa4c2021-02-23 16:59:25 +08003051 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003052
Vijay Khemka04175c22020-10-09 14:28:11 -07003053#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003054 // Chassis System Service
3055 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003056 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003057
3058 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003059 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003060 "/xyz/openbmc_project/state/chassis_system0",
3061 "xyz.openbmc_project.State.Chassis");
3062
Lei YU92caa4c2021-02-23 16:59:25 +08003063 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003064 "RequestedPowerTransition",
3065 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3066 [](const std::string& requested, std::string& resp) {
3067 if (requested ==
3068 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3069 {
Lei YU92caa4c2021-02-23 16:59:25 +08003070 systemReset();
3071 addRestartCause(RestartCause::command);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003072 }
3073 else
3074 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003075 phosphor::logging::log<phosphor::logging::level::ERR>(
3076 "Unrecognized chassis system state transition request.");
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003077 throw std::invalid_argument("Unrecognized Transition Request");
3078 return 0;
3079 }
3080 resp = requested;
3081 return 1;
3082 });
Lei YU92caa4c2021-02-23 16:59:25 +08003083 chassisSysIface->register_property(
3084 "CurrentPowerState", std::string(getChassisState(powerState)));
3085 chassisSysIface->register_property("LastStateChangeTime",
3086 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003087
Lei YU92caa4c2021-02-23 16:59:25 +08003088 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003089
Naveen Moses117c34e2021-05-26 20:10:51 +05303090 if (!slotPowerConfig.lineName.empty())
3091 {
3092 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3093 {
3094 return -1;
3095 }
3096
3097 slotPowerState = SlotPowerState::off;
3098 if (slotPowerLine.get_value() > 0)
3099 {
3100 slotPowerState = SlotPowerState::on;
3101 }
3102
3103 chassisSlotIface = chassisSysServer.add_interface(
3104 "/xyz/openbmc_project/state/chassis_system" + node,
3105 "xyz.openbmc_project.State.Chassis");
3106 chassisSlotIface->register_property(
3107 "RequestedPowerTransition",
3108 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3109 [](const std::string& requested, std::string& resp) {
3110 if (requested ==
3111 "xyz.openbmc_project.State.Chassis.Transition.On")
3112 {
3113 slotPowerOn();
3114 }
3115 else if (requested ==
3116 "xyz.openbmc_project.State.Chassis.Transition.Off")
3117 {
3118 slotPowerOff();
3119 }
3120 else if (requested == "xyz.openbmc_project.State.Chassis."
3121 "Transition.PowerCycle")
3122 {
3123 slotPowerCycle();
3124 }
3125 else
3126 {
3127 phosphor::logging::log<phosphor::logging::level::ERR>(
3128 "Unrecognized chassis system state transition "
3129 "request.\n");
3130 throw std::invalid_argument(
3131 "Unrecognized Transition Request");
3132 return 0;
3133 }
3134 resp = requested;
3135 return 1;
3136 });
3137 chassisSlotIface->register_property(
3138 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3139 chassisSlotIface->register_property("LastStateChangeTime",
3140 getCurrentTimeMs());
3141 chassisSlotIface->initialize();
3142 }
3143#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003144 // Buttons Service
3145 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003146 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003147
Priyatharshan P70120512020-09-16 18:47:20 +05303148 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003149 {
Priyatharshan P70120512020-09-16 18:47:20 +05303150 // Power Button Interface
3151 power_control::powerButtonIface = buttonsServer.add_interface(
3152 "/xyz/openbmc_project/chassis/buttons/power",
3153 "xyz.openbmc_project.Chassis.Buttons");
3154
3155 powerButtonIface->register_property(
3156 "ButtonMasked", false, [](const bool requested, bool& current) {
3157 if (requested)
3158 {
3159 if (powerButtonMask)
3160 {
3161 return 1;
3162 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003163 if (!setGPIOOutput(powerOutConfig.lineName,
3164 !powerOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303165 powerButtonMask))
3166 {
3167 throw std::runtime_error("Failed to request GPIO");
3168 return 0;
3169 }
3170 phosphor::logging::log<phosphor::logging::level::INFO>(
3171 "Power Button Masked.");
3172 }
3173 else
3174 {
3175 if (!powerButtonMask)
3176 {
3177 return 1;
3178 }
3179 phosphor::logging::log<phosphor::logging::level::INFO>(
3180 "Power Button Un-masked");
3181 powerButtonMask.reset();
3182 }
3183 // Update the mask setting
3184 current = requested;
3185 return 1;
3186 });
3187
3188 // Check power button state
3189 bool powerButtonPressed;
3190 if (powerButtonConfig.type == ConfigType::GPIO)
3191 {
3192 powerButtonPressed = powerButtonLine.get_value() == 0;
3193 }
3194 else
3195 {
3196 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3197 }
3198
3199 powerButtonIface->register_property("ButtonPressed",
3200 powerButtonPressed);
3201
3202 powerButtonIface->initialize();
3203 }
3204
3205 if (!resetButtonConfig.lineName.empty())
3206 {
3207 // Reset Button Interface
3208
Lei YU92caa4c2021-02-23 16:59:25 +08003209 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003210 "/xyz/openbmc_project/chassis/buttons/reset",
3211 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003212
Lei YU92caa4c2021-02-23 16:59:25 +08003213 resetButtonIface->register_property(
John Wang6c090072020-09-30 13:32:16 +08003214 "ButtonMasked", false, [](const bool requested, bool& current) {
3215 if (requested)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003216 {
Lei YU92caa4c2021-02-23 16:59:25 +08003217 if (resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003218 {
3219 return 1;
3220 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003221 if (!setGPIOOutput(resetOutConfig.lineName,
3222 !resetOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303223 resetButtonMask))
John Wang6c090072020-09-30 13:32:16 +08003224 {
3225 throw std::runtime_error("Failed to request GPIO");
3226 return 0;
3227 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003228 phosphor::logging::log<phosphor::logging::level::INFO>(
3229 "Reset Button Masked.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003230 }
John Wang6c090072020-09-30 13:32:16 +08003231 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003232 {
Lei YU92caa4c2021-02-23 16:59:25 +08003233 if (!resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003234 {
3235 return 1;
3236 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003237 phosphor::logging::log<phosphor::logging::level::INFO>(
3238 "Reset Button Un-masked");
Lei YU92caa4c2021-02-23 16:59:25 +08003239 resetButtonMask.reset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003240 }
John Wang6c090072020-09-30 13:32:16 +08003241 // Update the mask setting
3242 current = requested;
3243 return 1;
3244 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003245
John Wang6c090072020-09-30 13:32:16 +08003246 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303247 bool resetButtonPressed;
3248 if (resetButtonConfig.type == ConfigType::GPIO)
3249 {
3250 resetButtonPressed = resetButtonLine.get_value() == 0;
3251 }
3252 else
3253 {
3254 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3255 }
3256
Lei YU92caa4c2021-02-23 16:59:25 +08003257 resetButtonIface->register_property("ButtonPressed",
3258 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003259
Lei YU92caa4c2021-02-23 16:59:25 +08003260 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003261 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003262
Lei YU92caa4c2021-02-23 16:59:25 +08003263 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003264 {
3265 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003266 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003267 "/xyz/openbmc_project/chassis/buttons/nmi",
3268 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003269
Lei YU92caa4c2021-02-23 16:59:25 +08003270 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003271 "ButtonMasked", false, [](const bool requested, bool& current) {
Lei YU92caa4c2021-02-23 16:59:25 +08003272 if (nmiButtonMasked == requested)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003273 {
3274 // NMI button mask is already set as requested, so no change
3275 return 1;
3276 }
3277 if (requested)
3278 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003279 phosphor::logging::log<phosphor::logging::level::INFO>(
3280 "NMI Button Masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003281 nmiButtonMasked = true;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003282 }
3283 else
3284 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003285 phosphor::logging::log<phosphor::logging::level::INFO>(
3286 "NMI Button Un-masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003287 nmiButtonMasked = false;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003288 }
3289 // Update the mask setting
Lei YU92caa4c2021-02-23 16:59:25 +08003290 current = nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003291 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003292 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003293
Vijay Khemka33a532d2019-11-14 16:50:35 -08003294 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303295 bool nmiButtonPressed;
3296 if (nmiButtonConfig.type == ConfigType::GPIO)
3297 {
3298 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3299 }
3300 else
3301 {
3302 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3303 }
3304
Lei YU92caa4c2021-02-23 16:59:25 +08003305 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003306
Lei YU92caa4c2021-02-23 16:59:25 +08003307 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003308 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003309
Lei YU92caa4c2021-02-23 16:59:25 +08003310 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003311 {
3312 // NMI out Service
3313 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003314 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003315
Vijay Khemka33a532d2019-11-14 16:50:35 -08003316 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303317 nmiOutIface = nmiOutServer.add_interface(
3318 "/xyz/openbmc_project/control/host" + node + "/nmi",
3319 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003320 nmiOutIface->register_method("NMI", nmiReset);
3321 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003322 }
Chen Yugang174ec662019-08-19 19:58:49 +08003323
Lei YU92caa4c2021-02-23 16:59:25 +08003324 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003325 {
3326 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003327 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003328 "/xyz/openbmc_project/chassis/buttons/id",
3329 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003330
Vijay Khemka33a532d2019-11-14 16:50:35 -08003331 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303332 bool idButtonPressed;
3333 if (idButtonConfig.type == ConfigType::GPIO)
3334 {
3335 idButtonPressed = idButtonLine.get_value() == 0;
3336 }
3337 else
3338 {
3339 idButtonPressed = getProperty(idButtonConfig) == 0;
3340 }
3341
Lei YU92caa4c2021-02-23 16:59:25 +08003342 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003343
Lei YU92caa4c2021-02-23 16:59:25 +08003344 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003345 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003346
3347 // OS State Service
3348 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003349 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003350
3351 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003352 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003353 "/xyz/openbmc_project/state/os",
3354 "xyz.openbmc_project.State.OperatingSystem.Status");
3355
3356 // Get the initial OS state based on POST complete
3357 // 0: Asserted, OS state is "Standby" (ready to boot)
3358 // 1: De-Asserted, OS state is "Inactive"
Priyatharshan P70120512020-09-16 18:47:20 +05303359 std::string osState;
3360 if (postCompleteConfig.type == ConfigType::GPIO)
3361 {
3362 osState = postCompleteLine.get_value() > 0 ? "Inactive" : "Standby";
3363 }
3364 else
3365 {
3366 osState = getProperty(postCompleteConfig) > 0 ? "Inactive" : "Standby";
3367 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003368
Lei YU92caa4c2021-02-23 16:59:25 +08003369 osIface->register_property("OperatingSystemState", std::string(osState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003370
Lei YU92caa4c2021-02-23 16:59:25 +08003371 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003372
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003373 // Restart Cause Service
3374 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003375 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003376
3377 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003378 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303379 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003380 "xyz.openbmc_project.Control.Host.RestartCause");
3381
Lei YU92caa4c2021-02-23 16:59:25 +08003382 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003383 "RestartCause",
3384 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3385
Lei YU92caa4c2021-02-23 16:59:25 +08003386 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003387 "RequestedRestartCause",
3388 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3389 [](const std::string& requested, std::string& resp) {
3390 if (requested ==
3391 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3392 {
Lei YU92caa4c2021-02-23 16:59:25 +08003393 addRestartCause(RestartCause::watchdog);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003394 }
3395 else
3396 {
3397 throw std::invalid_argument(
3398 "Unrecognized RestartCause Request");
3399 return 0;
3400 }
3401
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003402 std::string logMsg = "RestartCause requested: " + requested;
3403 phosphor::logging::log<phosphor::logging::level::INFO>(
3404 logMsg.c_str());
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003405 resp = requested;
3406 return 1;
3407 });
3408
Lei YU92caa4c2021-02-23 16:59:25 +08003409 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003410
Lei YU92caa4c2021-02-23 16:59:25 +08003411 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003412
Lei YU92caa4c2021-02-23 16:59:25 +08003413 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003414
3415 return 0;
3416}