blob: d7899b34c8129bb61603956d36ac20341052d809 [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 = {
Jason M. Billsaeefe042021-09-08 14:56:11 -0700130 {"PowerPulseMs", 200},
131 {"ForceOffPulseMs", 15000},
132 {"ResetPulseMs", 500},
133 {"PowerCycleMs", 5000},
134 {"SioPowerGoodWatchdogMs", 1000},
135 {"PsPowerOKWatchdogMs", 8000},
136 {"GracefulPowerOffS", (5 * 60)},
137 {"WarmResetCheckMs", 500},
138 {"PowerOffSaveMs", 7000},
139 {"SlotPowerCycleMs", 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(
Jason M. Billsaeefe042021-09-08 14:56:11 -0700546 std::chrono::milliseconds(TimerMap["PowerOffSaveMs"]));
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",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700705 TimerMap["SioPowerGoodWatchdogMs"], 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",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700714 TimerMap["PsPowerOKWatchdogMs"], 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 // If the requested GPIO is masked, use the mask line to set the output
1194 if (powerButtonMask && config.lineName == powerOutConfig.lineName)
1195 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001196 return setMaskedGPIOOutputForMs(powerButtonMask, config.lineName, value,
1197 durationMs);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001198 }
1199 if (resetButtonMask && config.lineName == resetOutConfig.lineName)
1200 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001201 return setMaskedGPIOOutputForMs(resetButtonMask, config.lineName, value,
1202 durationMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001203 }
1204
1205 // No mask set, so request and set the GPIO normally
1206 gpiod::line gpioLine;
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001207 if (!setGPIOOutput(config.lineName, value, gpioLine))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001208 {
1209 return -1;
1210 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001211 const std::string name = config.lineName;
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001212
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001213 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001214 gpioAssertTimer.async_wait([gpioLine, value,
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001215 name](const boost::system::error_code ec) {
1216 // Set the GPIO line back to the opposite value
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001217 gpioLine.set_value(!value);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001218 std::string logMsg = name + " released";
1219 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
1220 if (ec)
1221 {
1222 // operation_aborted is expected if timer is canceled before
1223 // completion.
1224 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001225 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001226 std::string errMsg =
1227 name + " async_wait failed: " + ec.message();
1228 phosphor::logging::log<phosphor::logging::level::ERR>(
1229 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001230 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001231 }
1232 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001233 return 0;
1234}
1235
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001236static int assertGPIOForMs(const ConfigData& config, const int durationMs)
1237{
1238 return setGPIOOutputForMs(config, config.polarity, durationMs);
1239}
1240
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001241static void powerOn()
1242{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001243 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001244}
Naveen Moses117c34e2021-05-26 20:10:51 +05301245#ifdef CHASSIS_SYSTEM_RESET
1246static int slotPowerOn()
1247{
1248 if (power_control::slotPowerState != power_control::SlotPowerState::on)
1249 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001250
Naveen Moses117c34e2021-05-26 20:10:51 +05301251 slotPowerLine.set_value(1);
1252
1253 if (slotPowerLine.get_value() > 0)
1254 {
1255 setSlotPowerState(SlotPowerState::on);
1256 phosphor::logging::log<phosphor::logging::level::INFO>(
1257 "Slot Power is switched On\n");
1258 }
1259 else
1260 {
1261 return -1;
1262 }
1263 }
1264 else
1265 {
1266 phosphor::logging::log<phosphor::logging::level::INFO>(
1267 "Slot Power is already in 'On' state\n");
1268 return -1;
1269 }
1270 return 0;
1271}
1272static int slotPowerOff()
1273{
1274 if (power_control::slotPowerState != power_control::SlotPowerState::off)
1275 {
1276 slotPowerLine.set_value(0);
1277
1278 if (!(slotPowerLine.get_value() > 0))
1279 {
1280 setSlotPowerState(SlotPowerState::off);
1281 setPowerState(PowerState::off);
1282 phosphor::logging::log<phosphor::logging::level::INFO>(
1283 "Slot Power is switched Off\n");
1284 }
1285 else
1286 {
1287 return -1;
1288 }
1289 }
1290 else
1291 {
1292 phosphor::logging::log<phosphor::logging::level::INFO>(
1293 "Slot Power is already in 'Off' state\n");
1294 return -1;
1295 }
1296 return 0;
1297}
1298static void slotPowerCycle()
1299{
1300 phosphor::logging::log<phosphor::logging::level::INFO>(
1301 "Slot Power Cycle started\n");
1302 slotPowerOff();
1303 slotPowerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001304 std::chrono::milliseconds(TimerMap["SlotPowerCycleMs"]));
Naveen Moses117c34e2021-05-26 20:10:51 +05301305 slotPowerCycleTimer.async_wait([](const boost::system::error_code ec) {
1306 if (ec)
1307 {
1308 if (ec != boost::asio::error::operation_aborted)
1309 {
1310 std::string errMsg =
1311 "Slot Power cycle timer async_wait failed: " + ec.message();
1312 phosphor::logging::log<phosphor::logging::level::ERR>(
1313 errMsg.c_str());
1314 }
1315 phosphor::logging::log<phosphor::logging::level::INFO>(
1316 "Slot Power cycle timer canceled\n");
1317 return;
1318 }
1319 phosphor::logging::log<phosphor::logging::level::INFO>(
1320 "Slot Power cycle timer completed\n");
1321 slotPowerOn();
1322 phosphor::logging::log<phosphor::logging::level::INFO>(
1323 "Slot Power Cycle Completed\n");
1324 });
1325}
1326#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001327static void gracefulPowerOff()
1328{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001329 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001330}
1331
1332static void forcePowerOff()
1333{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001334 if (assertGPIOForMs(powerOutConfig, TimerMap["ForceOffPulseMs"]) < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001335 {
1336 return;
1337 }
1338
1339 // If the force off timer expires, then the PCH power-button override
1340 // failed, so attempt the Unconditional Powerdown SMBus command.
1341 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1342 if (ec)
1343 {
1344 // operation_aborted is expected if timer is canceled before
1345 // completion.
1346 if (ec != boost::asio::error::operation_aborted)
1347 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001348 std::string errMsg =
1349 "Force power off async_wait failed: " + ec.message();
1350 phosphor::logging::log<phosphor::logging::level::ERR>(
1351 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001352 }
1353 return;
1354 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001355
1356 phosphor::logging::log<phosphor::logging::level::INFO>(
1357 "PCH Power-button override failed. Issuing Unconditional Powerdown "
1358 "SMBus command.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001359 const static constexpr size_t pchDevBusAddress = 3;
1360 const static constexpr size_t pchDevSlaveAddress = 0x44;
1361 const static constexpr size_t pchCmdReg = 0;
1362 const static constexpr size_t pchPowerDownCmd = 0x02;
1363 if (i2cSet(pchDevBusAddress, pchDevSlaveAddress, pchCmdReg,
1364 pchPowerDownCmd) < 0)
1365 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001366 phosphor::logging::log<phosphor::logging::level::ERR>(
1367 "Unconditional Powerdown command failed! Not sure what to do "
1368 "now.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001369 }
1370 });
1371}
1372
1373static void reset()
1374{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001375 assertGPIOForMs(resetOutConfig, TimerMap["ResetPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001376}
1377
1378static void gracefulPowerOffTimerStart()
1379{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001380 phosphor::logging::log<phosphor::logging::level::INFO>(
1381 "Graceful power-off timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001382 gracefulPowerOffTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001383 std::chrono::seconds(TimerMap["GracefulPowerOffS"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001384 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1385 if (ec)
1386 {
1387 // operation_aborted is expected if timer is canceled before
1388 // completion.
1389 if (ec != boost::asio::error::operation_aborted)
1390 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001391 std::string errMsg =
1392 "Graceful power-off async_wait failed: " + ec.message();
1393 phosphor::logging::log<phosphor::logging::level::ERR>(
1394 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001395 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001396 phosphor::logging::log<phosphor::logging::level::INFO>(
1397 "Graceful power-off timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001398 return;
1399 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001400 phosphor::logging::log<phosphor::logging::level::INFO>(
1401 "Graceful power-off timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001402 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1403 });
1404}
1405
1406static void powerCycleTimerStart()
1407{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001408 phosphor::logging::log<phosphor::logging::level::INFO>(
1409 "Power-cycle timer started");
Priyatharshan P70120512020-09-16 18:47:20 +05301410 powerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001411 std::chrono::milliseconds(TimerMap["PowerCycleMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001412 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1413 if (ec)
1414 {
1415 // operation_aborted is expected if timer is canceled before
1416 // completion.
1417 if (ec != boost::asio::error::operation_aborted)
1418 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001419 std::string errMsg =
1420 "Power-cycle async_wait failed: " + ec.message();
1421 phosphor::logging::log<phosphor::logging::level::ERR>(
1422 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001423 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001424 phosphor::logging::log<phosphor::logging::level::INFO>(
1425 "Power-cycle timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001426 return;
1427 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001428 phosphor::logging::log<phosphor::logging::level::INFO>(
1429 "Power-cycle timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001430 sendPowerControlEvent(Event::powerCycleTimerExpired);
1431 });
1432}
1433
1434static void psPowerOKWatchdogTimerStart()
1435{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001436 phosphor::logging::log<phosphor::logging::level::INFO>(
1437 "power supply power OK watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001438 psPowerOKWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001439 std::chrono::milliseconds(TimerMap["PsPowerOKWatchdogMs"]));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001440 psPowerOKWatchdogTimer.async_wait([](const boost::system::error_code ec) {
1441 if (ec)
1442 {
1443 // operation_aborted is expected if timer is canceled before
1444 // completion.
1445 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001446 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001447 std::string errMsg =
1448 "power supply power OK watchdog async_wait failed: " +
1449 ec.message();
1450 phosphor::logging::log<phosphor::logging::level::ERR>(
1451 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001452 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001453 phosphor::logging::log<phosphor::logging::level::INFO>(
1454 "power supply power OK watchdog timer canceled");
1455 return;
1456 }
1457 phosphor::logging::log<phosphor::logging::level::INFO>(
1458 "power supply power OK watchdog timer expired");
1459 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1460 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001461}
1462
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001463static void warmResetCheckTimerStart()
1464{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001465 phosphor::logging::log<phosphor::logging::level::INFO>(
1466 "Warm reset check timer started");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001467 warmResetCheckTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001468 std::chrono::milliseconds(TimerMap["WarmResetCheckMs"]));
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001469 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1470 if (ec)
1471 {
1472 // operation_aborted is expected if timer is canceled before
1473 // completion.
1474 if (ec != boost::asio::error::operation_aborted)
1475 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001476 std::string errMsg =
1477 "Warm reset check async_wait failed: " + ec.message();
1478 phosphor::logging::log<phosphor::logging::level::ERR>(
1479 errMsg.c_str());
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001480 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001481 phosphor::logging::log<phosphor::logging::level::INFO>(
1482 "Warm reset check timer canceled");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001483 return;
1484 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001485 phosphor::logging::log<phosphor::logging::level::INFO>(
1486 "Warm reset check timer completed");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001487 sendPowerControlEvent(Event::warmResetDetected);
1488 });
1489}
1490
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001491static void pohCounterTimerStart()
1492{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001493 phosphor::logging::log<phosphor::logging::level::INFO>("POH timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001494 // Set the time-out as 1 hour, to align with POH command in ipmid
1495 pohCounterTimer.expires_after(std::chrono::hours(1));
1496 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1497 if (ec)
1498 {
1499 // operation_aborted is expected if timer is canceled before
1500 // completion.
1501 if (ec != boost::asio::error::operation_aborted)
1502 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001503 std::string errMsg =
1504 "POH timer async_wait failed: " + ec.message();
1505 phosphor::logging::log<phosphor::logging::level::ERR>(
1506 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001507 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001508 phosphor::logging::log<phosphor::logging::level::INFO>(
1509 "POH timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001510 return;
1511 }
1512
1513 if (getHostState(powerState) !=
1514 "xyz.openbmc_project.State.Host.HostState.Running")
1515 {
1516 return;
1517 }
1518
1519 conn->async_method_call(
1520 [](boost::system::error_code ec,
1521 const std::variant<uint32_t>& pohCounterProperty) {
1522 if (ec)
1523 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001524 phosphor::logging::log<phosphor::logging::level::INFO>(
1525 "error to get poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001526 return;
1527 }
1528 const uint32_t* pohCounter =
1529 std::get_if<uint32_t>(&pohCounterProperty);
1530 if (pohCounter == nullptr)
1531 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001532 phosphor::logging::log<phosphor::logging::level::INFO>(
1533 "unable to read poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001534 return;
1535 }
1536
1537 conn->async_method_call(
1538 [](boost::system::error_code ec) {
1539 if (ec)
1540 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001541 phosphor::logging::log<
1542 phosphor::logging::level::INFO>(
1543 "failed to set poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001544 }
1545 },
1546 "xyz.openbmc_project.Settings",
1547 "/xyz/openbmc_project/state/chassis0",
1548 "org.freedesktop.DBus.Properties", "Set",
1549 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1550 std::variant<uint32_t>(*pohCounter + 1));
1551 },
1552 "xyz.openbmc_project.Settings",
1553 "/xyz/openbmc_project/state/chassis0",
1554 "org.freedesktop.DBus.Properties", "Get",
1555 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1556
1557 pohCounterTimerStart();
1558 });
1559}
1560
1561static void currentHostStateMonitor()
1562{
Yong Li8d660212019-12-27 10:18:10 +08001563 if (getHostState(powerState) ==
1564 "xyz.openbmc_project.State.Host.HostState.Running")
1565 {
1566 pohCounterTimerStart();
1567 // Clear the restart cause set for the next restart
1568 clearRestartCause();
1569 }
1570 else
1571 {
1572 pohCounterTimer.cancel();
1573 // Set the restart cause set for this restart
1574 setRestartCause();
1575 }
1576
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001577 static auto match = sdbusplus::bus::match::match(
1578 *conn,
1579 "type='signal',member='PropertiesChanged', "
1580 "interface='org.freedesktop.DBus.Properties', "
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001581 "arg0='xyz.openbmc_project.State.Host'",
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001582 [](sdbusplus::message::message& message) {
1583 std::string intfName;
1584 std::map<std::string, std::variant<std::string>> properties;
1585
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001586 try
1587 {
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001588 message.read(intfName, properties);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001589 }
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001590 catch (std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001591 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001592 phosphor::logging::log<phosphor::logging::level::ERR>(
1593 "Unable to read host state");
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001594 return;
1595 }
1596 if (properties.empty())
1597 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001598 phosphor::logging::log<phosphor::logging::level::ERR>(
1599 "ERROR: Empty PropertiesChanged signal received");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001600 return;
1601 }
1602
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001603 // We only want to check for CurrentHostState
1604 if (properties.begin()->first != "CurrentHostState")
1605 {
1606 return;
1607 }
1608 std::string* currentHostState =
1609 std::get_if<std::string>(&(properties.begin()->second));
1610 if (currentHostState == nullptr)
1611 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001612 std::string errMsg =
1613 properties.begin()->first + " property invalid";
1614 phosphor::logging::log<phosphor::logging::level::ERR>(
1615 errMsg.c_str());
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001616 return;
1617 }
1618
1619 if (*currentHostState ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001620 "xyz.openbmc_project.State.Host.HostState.Running")
1621 {
1622 pohCounterTimerStart();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001623 // Clear the restart cause set for the next restart
1624 clearRestartCause();
Yong Li8d660212019-12-27 10:18:10 +08001625 sd_journal_send("MESSAGE=Host system DC power is on",
1626 "PRIORITY=%i", LOG_INFO,
1627 "REDFISH_MESSAGE_ID=%s",
1628 "OpenBMC.0.1.DCPowerOn", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001629 }
1630 else
1631 {
1632 pohCounterTimer.cancel();
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301633 // POST_COMPLETE GPIO event is not working in some platforms
1634 // when power state is changed to OFF. This resulted in
1635 // 'OperatingSystemState' to stay at 'Standby', even though
1636 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1637 // if HostState is trurned to OFF.
1638 osIface->set_property("OperatingSystemState",
1639 std::string("Inactive"));
1640
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001641 // Set the restart cause set for this restart
1642 setRestartCause();
Rashmi RV89f61312020-01-22 15:41:50 +05301643 resetACBootProperty();
Yong Li8d660212019-12-27 10:18:10 +08001644 sd_journal_send("MESSAGE=Host system DC power is off",
1645 "PRIORITY=%i", LOG_INFO,
1646 "REDFISH_MESSAGE_ID=%s",
1647 "OpenBMC.0.1.DCPowerOff", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001648 }
1649 });
1650}
1651
1652static void sioPowerGoodWatchdogTimerStart()
1653{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001654 phosphor::logging::log<phosphor::logging::level::INFO>(
1655 "SIO power good watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001656 sioPowerGoodWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001657 std::chrono::milliseconds(TimerMap["SioPowerGoodWatchdogMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001658 sioPowerGoodWatchdogTimer.async_wait(
1659 [](const boost::system::error_code ec) {
1660 if (ec)
1661 {
1662 // operation_aborted is expected if timer is canceled before
1663 // completion.
1664 if (ec != boost::asio::error::operation_aborted)
1665 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001666 std::string errMsg =
1667 "SIO power good watchdog async_wait failed: " +
1668 ec.message();
1669 phosphor::logging::log<phosphor::logging::level::ERR>(
1670 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001671 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001672 phosphor::logging::log<phosphor::logging::level::INFO>(
1673 "SIO power good watchdog timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001674 return;
1675 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001676 phosphor::logging::log<phosphor::logging::level::INFO>(
1677 "SIO power good watchdog timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001678 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1679 });
1680}
1681
1682static void powerStateOn(const Event event)
1683{
1684 logEvent(__FUNCTION__, event);
1685 switch (event)
1686 {
1687 case Event::psPowerOKDeAssert:
1688 setPowerState(PowerState::off);
1689 // DC power is unexpectedly lost, beep
1690 beep(beepPowerFail);
1691 break;
1692 case Event::sioS5Assert:
1693 setPowerState(PowerState::transitionToOff);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001694 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001695 break;
Jason M. Billsfb957332021-01-28 13:18:46 -08001696#if USE_PLT_RST
1697 case Event::pltRstAssert:
1698#else
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001699 case Event::postCompleteDeAssert:
Jason M. Billsfb957332021-01-28 13:18:46 -08001700#endif
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001701 setPowerState(PowerState::checkForWarmReset);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001702 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001703 warmResetCheckTimerStart();
1704 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001705 case Event::powerButtonPressed:
1706 setPowerState(PowerState::gracefulTransitionToOff);
1707 gracefulPowerOffTimerStart();
1708 break;
1709 case Event::powerOffRequest:
1710 setPowerState(PowerState::transitionToOff);
1711 forcePowerOff();
1712 break;
1713 case Event::gracefulPowerOffRequest:
1714 setPowerState(PowerState::gracefulTransitionToOff);
1715 gracefulPowerOffTimerStart();
1716 gracefulPowerOff();
1717 break;
1718 case Event::powerCycleRequest:
1719 setPowerState(PowerState::transitionToCycleOff);
1720 forcePowerOff();
1721 break;
1722 case Event::gracefulPowerCycleRequest:
1723 setPowerState(PowerState::gracefulTransitionToCycleOff);
1724 gracefulPowerOffTimerStart();
1725 gracefulPowerOff();
1726 break;
1727 case Event::resetRequest:
1728 reset();
1729 break;
1730 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001731 phosphor::logging::log<phosphor::logging::level::INFO>(
1732 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001733 break;
1734 }
1735}
1736
1737static void powerStateWaitForPSPowerOK(const Event event)
1738{
1739 logEvent(__FUNCTION__, event);
1740 switch (event)
1741 {
1742 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301743 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001744 // Cancel any GPIO assertions held during the transition
1745 gpioAssertTimer.cancel();
1746 psPowerOKWatchdogTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301747 if (sioEnabled == true)
1748 {
1749 sioPowerGoodWatchdogTimerStart();
1750 setPowerState(PowerState::waitForSIOPowerGood);
1751 }
1752 else
1753 {
1754 setPowerState(PowerState::on);
1755 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001756 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301757 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001758 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001759 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001760 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001761 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001762 case Event::sioPowerGoodAssert:
1763 psPowerOKWatchdogTimer.cancel();
1764 setPowerState(PowerState::on);
1765 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001766 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001767 phosphor::logging::log<phosphor::logging::level::INFO>(
1768 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001769 break;
1770 }
1771}
1772
1773static void powerStateWaitForSIOPowerGood(const Event event)
1774{
1775 logEvent(__FUNCTION__, event);
1776 switch (event)
1777 {
1778 case Event::sioPowerGoodAssert:
1779 sioPowerGoodWatchdogTimer.cancel();
1780 setPowerState(PowerState::on);
1781 break;
1782 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001783 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001784 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001785 break;
1786 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001787 phosphor::logging::log<phosphor::logging::level::INFO>(
1788 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001789 break;
1790 }
1791}
1792
1793static void powerStateOff(const Event event)
1794{
1795 logEvent(__FUNCTION__, event);
1796 switch (event)
1797 {
1798 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301799 {
1800 if (sioEnabled == true)
1801 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001802 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301803 setPowerState(PowerState::waitForSIOPowerGood);
1804 }
1805 else
1806 {
1807 setPowerState(PowerState::on);
1808 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001809 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301810 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001811 case Event::sioS5DeAssert:
1812 setPowerState(PowerState::waitForPSPowerOK);
1813 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001814 case Event::sioPowerGoodAssert:
1815 setPowerState(PowerState::on);
1816 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001817 case Event::powerButtonPressed:
1818 psPowerOKWatchdogTimerStart();
1819 setPowerState(PowerState::waitForPSPowerOK);
1820 break;
1821 case Event::powerOnRequest:
1822 psPowerOKWatchdogTimerStart();
1823 setPowerState(PowerState::waitForPSPowerOK);
1824 powerOn();
1825 break;
1826 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001827 phosphor::logging::log<phosphor::logging::level::INFO>(
1828 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001829 break;
1830 }
1831}
1832
1833static void powerStateTransitionToOff(const Event event)
1834{
1835 logEvent(__FUNCTION__, event);
1836 switch (event)
1837 {
1838 case Event::psPowerOKDeAssert:
1839 // Cancel any GPIO assertions held during the transition
1840 gpioAssertTimer.cancel();
1841 setPowerState(PowerState::off);
1842 break;
1843 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001844 phosphor::logging::log<phosphor::logging::level::INFO>(
1845 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001846 break;
1847 }
1848}
1849
1850static void powerStateGracefulTransitionToOff(const Event event)
1851{
1852 logEvent(__FUNCTION__, event);
1853 switch (event)
1854 {
1855 case Event::psPowerOKDeAssert:
1856 gracefulPowerOffTimer.cancel();
1857 setPowerState(PowerState::off);
1858 break;
1859 case Event::gracefulPowerOffTimerExpired:
1860 setPowerState(PowerState::on);
1861 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001862 case Event::powerOffRequest:
1863 gracefulPowerOffTimer.cancel();
1864 setPowerState(PowerState::transitionToOff);
1865 forcePowerOff();
1866 break;
1867 case Event::powerCycleRequest:
1868 gracefulPowerOffTimer.cancel();
1869 setPowerState(PowerState::transitionToCycleOff);
1870 forcePowerOff();
1871 break;
1872 case Event::resetRequest:
1873 gracefulPowerOffTimer.cancel();
1874 setPowerState(PowerState::on);
1875 reset();
1876 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001877 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001878 phosphor::logging::log<phosphor::logging::level::INFO>(
1879 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001880 break;
1881 }
1882}
1883
1884static void powerStateCycleOff(const Event event)
1885{
1886 logEvent(__FUNCTION__, event);
1887 switch (event)
1888 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001889 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301890 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001891 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301892 if (sioEnabled == true)
1893 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001894 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301895 setPowerState(PowerState::waitForSIOPowerGood);
1896 }
1897 else
1898 {
1899 setPowerState(PowerState::on);
1900 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001901 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301902 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001903 case Event::sioS5DeAssert:
1904 powerCycleTimer.cancel();
1905 setPowerState(PowerState::waitForPSPowerOK);
1906 break;
1907 case Event::powerButtonPressed:
1908 powerCycleTimer.cancel();
1909 psPowerOKWatchdogTimerStart();
1910 setPowerState(PowerState::waitForPSPowerOK);
1911 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001912 case Event::powerCycleTimerExpired:
1913 psPowerOKWatchdogTimerStart();
1914 setPowerState(PowerState::waitForPSPowerOK);
1915 powerOn();
1916 break;
1917 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001918 phosphor::logging::log<phosphor::logging::level::INFO>(
1919 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001920 break;
1921 }
1922}
1923
1924static void powerStateTransitionToCycleOff(const Event event)
1925{
1926 logEvent(__FUNCTION__, event);
1927 switch (event)
1928 {
1929 case Event::psPowerOKDeAssert:
1930 // Cancel any GPIO assertions held during the transition
1931 gpioAssertTimer.cancel();
1932 setPowerState(PowerState::cycleOff);
1933 powerCycleTimerStart();
1934 break;
1935 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001936 phosphor::logging::log<phosphor::logging::level::INFO>(
1937 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001938 break;
1939 }
1940}
1941
1942static void powerStateGracefulTransitionToCycleOff(const Event event)
1943{
1944 logEvent(__FUNCTION__, event);
1945 switch (event)
1946 {
1947 case Event::psPowerOKDeAssert:
1948 gracefulPowerOffTimer.cancel();
1949 setPowerState(PowerState::cycleOff);
1950 powerCycleTimerStart();
1951 break;
1952 case Event::gracefulPowerOffTimerExpired:
1953 setPowerState(PowerState::on);
1954 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001955 case Event::powerOffRequest:
1956 gracefulPowerOffTimer.cancel();
1957 setPowerState(PowerState::transitionToOff);
1958 forcePowerOff();
1959 break;
1960 case Event::powerCycleRequest:
1961 gracefulPowerOffTimer.cancel();
1962 setPowerState(PowerState::transitionToCycleOff);
1963 forcePowerOff();
1964 break;
1965 case Event::resetRequest:
1966 gracefulPowerOffTimer.cancel();
1967 setPowerState(PowerState::on);
1968 reset();
1969 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001970 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001971 phosphor::logging::log<phosphor::logging::level::INFO>(
1972 "No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001973 break;
1974 }
1975}
1976
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001977static void powerStateCheckForWarmReset(const Event event)
1978{
1979 logEvent(__FUNCTION__, event);
1980 switch (event)
1981 {
1982 case Event::sioS5Assert:
1983 warmResetCheckTimer.cancel();
1984 setPowerState(PowerState::transitionToOff);
1985 break;
1986 case Event::warmResetDetected:
1987 setPowerState(PowerState::on);
1988 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001989 case Event::psPowerOKDeAssert:
1990 warmResetCheckTimer.cancel();
1991 setPowerState(PowerState::off);
1992 // DC power is unexpectedly lost, beep
1993 beep(beepPowerFail);
1994 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001995 default:
Jason M. Bills95f631c2020-06-17 14:04:29 -07001996 phosphor::logging::log<phosphor::logging::level::INFO>(
1997 "No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001998 break;
1999 }
2000}
2001
Zev Weiss584aa132021-09-02 19:21:52 -05002002static void psPowerOKHandler(bool state)
2003{
2004 Event powerControlEvent =
2005 state ? Event::psPowerOKAssert : Event::psPowerOKDeAssert;
2006 sendPowerControlEvent(powerControlEvent);
2007}
2008
Zev Weiss584aa132021-09-02 19:21:52 -05002009static void sioPowerGoodHandler(bool state)
2010{
2011 Event powerControlEvent =
2012 state ? Event::sioPowerGoodAssert : Event::sioPowerGoodDeAssert;
2013 sendPowerControlEvent(powerControlEvent);
2014}
2015
Zev Weiss584aa132021-09-02 19:21:52 -05002016static void sioOnControlHandler(bool state)
2017{
2018 std::string logMsg =
2019 "SIO_ONCONTROL value changed: " + std::to_string(state);
2020 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
2021}
2022
Zev Weiss584aa132021-09-02 19:21:52 -05002023static void sioS5Handler(bool state)
2024{
2025 Event powerControlEvent = state ? Event::sioS5DeAssert : Event::sioS5Assert;
2026 sendPowerControlEvent(powerControlEvent);
2027}
2028
Zev Weiss584aa132021-09-02 19:21:52 -05002029static void powerButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002030{
Zev Weiss584aa132021-09-02 19:21:52 -05002031 powerButtonIface->set_property("ButtonPressed", !state);
2032 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002033 {
2034 powerButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002035 if (!powerButtonMask)
2036 {
2037 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002038 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002039 }
2040 else
2041 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002042 phosphor::logging::log<phosphor::logging::level::INFO>(
2043 "power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002044 }
2045 }
Zev Weiss584aa132021-09-02 19:21:52 -05002046}
2047
Zev Weiss584aa132021-09-02 19:21:52 -05002048static void resetButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002049{
Zev Weiss584aa132021-09-02 19:21:52 -05002050 resetButtonIface->set_property("ButtonPressed", !state);
2051 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002052 {
2053 resetButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002054 if (!resetButtonMask)
2055 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002056 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002057 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002058 }
2059 else
2060 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002061 phosphor::logging::log<phosphor::logging::level::INFO>(
2062 "reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002063 }
2064 }
Zev Weiss584aa132021-09-02 19:21:52 -05002065}
2066
Vijay Khemka04175c22020-10-09 14:28:11 -07002067#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002068static constexpr auto systemdBusname = "org.freedesktop.systemd1";
2069static constexpr auto systemdPath = "/org/freedesktop/systemd1";
2070static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
2071static constexpr auto systemTargetName = "chassis-system-reset.target";
2072
2073void systemReset()
2074{
2075 conn->async_method_call(
2076 [](boost::system::error_code ec) {
2077 if (ec)
2078 {
2079 phosphor::logging::log<phosphor::logging::level::ERR>(
2080 "Failed to call chassis system reset",
2081 phosphor::logging::entry("ERR=%s", ec.message().c_str()));
2082 }
2083 },
2084 systemdBusname, systemdPath, systemdInterface, "StartUnit",
2085 systemTargetName, "replace");
2086}
Vijay Khemka04175c22020-10-09 14:28:11 -07002087#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002088
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002089static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002090{
2091 conn->async_method_call(
2092 [](boost::system::error_code ec) {
2093 if (ec)
2094 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002095 phosphor::logging::log<phosphor::logging::level::INFO>(
2096 "failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002097 }
2098 },
Chen Yugang303bd582019-11-01 08:45:06 +08002099 "xyz.openbmc_project.Settings",
2100 "/xyz/openbmc_project/Chassis/Control/NMISource",
2101 "org.freedesktop.DBus.Properties", "Set",
2102 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
2103 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002104}
2105
2106static void nmiReset(void)
2107{
2108 static constexpr const uint8_t value = 1;
2109 const static constexpr int nmiOutPulseTimeMs = 200;
2110
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002111 phosphor::logging::log<phosphor::logging::level::INFO>("NMI out action");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002112 nmiOutLine.set_value(value);
Priyatharshan P70120512020-09-16 18:47:20 +05302113 std::string logMsg =
2114 nmiOutConfig.lineName + " set to " + std::to_string(value);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002115 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002116 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2117 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2118 // restore the NMI_OUT GPIO line back to the opposite value
2119 nmiOutLine.set_value(!value);
Priyatharshan P70120512020-09-16 18:47:20 +05302120 std::string logMsg = nmiOutConfig.lineName + " released";
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002121 phosphor::logging::log<phosphor::logging::level::INFO>(logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002122 if (ec)
2123 {
2124 // operation_aborted is expected if timer is canceled before
2125 // completion.
2126 if (ec != boost::asio::error::operation_aborted)
2127 {
Priyatharshan P70120512020-09-16 18:47:20 +05302128 std::string errMsg = nmiOutConfig.lineName +
2129 " async_wait failed: " + ec.message();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002130 phosphor::logging::log<phosphor::logging::level::ERR>(
2131 errMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002132 }
2133 }
2134 });
2135 // log to redfish
2136 nmiDiagIntLog();
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002137 phosphor::logging::log<phosphor::logging::level::INFO>(
2138 "NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002139 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002140 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002141}
2142
2143static void nmiSourcePropertyMonitor(void)
2144{
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002145 phosphor::logging::log<phosphor::logging::level::INFO>(
2146 "NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002147
2148 static std::unique_ptr<sdbusplus::bus::match::match> nmiSourceMatch =
2149 std::make_unique<sdbusplus::bus::match::match>(
2150 *conn,
2151 "type='signal',interface='org.freedesktop.DBus.Properties',"
Chen Yugang303bd582019-11-01 08:45:06 +08002152 "member='PropertiesChanged',arg0namespace='xyz.openbmc_project."
2153 "Chassis.Control."
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002154 "NMISource'",
2155 [](sdbusplus::message::message& msg) {
2156 std::string interfaceName;
2157 boost::container::flat_map<std::string,
2158 std::variant<bool, std::string>>
2159 propertiesChanged;
2160 std::string state;
2161 bool value = true;
2162 try
2163 {
2164 msg.read(interfaceName, propertiesChanged);
2165 if (propertiesChanged.begin()->first == "Enabled")
2166 {
2167 value =
2168 std::get<bool>(propertiesChanged.begin()->second);
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002169 std::string logMsg =
2170 " NMI Enabled propertiesChanged value: " +
2171 std::to_string(value);
2172 phosphor::logging::log<phosphor::logging::level::INFO>(
2173 logMsg.c_str());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002174 nmiEnabled = value;
2175 if (nmiEnabled)
2176 {
2177 nmiReset();
2178 }
2179 }
2180 }
2181 catch (std::exception& e)
2182 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002183 phosphor::logging::log<phosphor::logging::level::ERR>(
2184 "Unable to read NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002185 return;
2186 }
2187 });
2188}
2189
2190static void setNmiSource()
2191{
2192 conn->async_method_call(
2193 [](boost::system::error_code ec) {
2194 if (ec)
2195 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002196 phosphor::logging::log<phosphor::logging::level::ERR>(
2197 "failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002198 }
2199 },
Chen Yugang303bd582019-11-01 08:45:06 +08002200 "xyz.openbmc_project.Settings",
2201 "/xyz/openbmc_project/Chassis/Control/NMISource",
2202 "org.freedesktop.DBus.Properties", "Set",
2203 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
2204 std::variant<std::string>{"xyz.openbmc_project.Chassis.Control."
2205 "NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002206 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002207 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002208}
2209
Zev Weiss584aa132021-09-02 19:21:52 -05002210static void nmiButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002211{
Zev Weiss584aa132021-09-02 19:21:52 -05002212 nmiButtonIface->set_property("ButtonPressed", !state);
2213 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002214 {
2215 nmiButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002216 if (nmiButtonMasked)
2217 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002218 phosphor::logging::log<phosphor::logging::level::INFO>(
2219 "NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002220 }
2221 else
2222 {
2223 setNmiSource();
2224 }
2225 }
Zev Weiss584aa132021-09-02 19:21:52 -05002226}
2227
Zev Weiss584aa132021-09-02 19:21:52 -05002228static void idButtonHandler(bool state)
2229{
2230 idButtonIface->set_property("ButtonPressed", !state);
2231}
2232
Jason M. Billsfb957332021-01-28 13:18:46 -08002233static void pltRstHandler(bool pltRst)
2234{
2235 if (pltRst)
2236 {
2237 sendPowerControlEvent(Event::pltRstDeAssert);
2238 }
2239 else
2240 {
2241 sendPowerControlEvent(Event::pltRstAssert);
2242 }
2243}
2244
2245static void hostMiscHandler(sdbusplus::message::message& msg)
2246{
2247 std::string interfaceName;
2248 boost::container::flat_map<std::string, std::variant<bool>>
2249 propertiesChanged;
2250 bool pltRst;
2251 try
2252 {
2253 msg.read(interfaceName, propertiesChanged);
2254 }
2255 catch (std::exception& e)
2256 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002257 phosphor::logging::log<phosphor::logging::level::ERR>(
2258 "Unable to read Host Misc status");
Jason M. Billsfb957332021-01-28 13:18:46 -08002259 return;
2260 }
2261 if (propertiesChanged.empty())
2262 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002263 phosphor::logging::log<phosphor::logging::level::ERR>(
2264 "ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002265 return;
2266 }
2267
2268 for (auto& [property, value] : propertiesChanged)
2269 {
2270 if (property == "ESpiPlatformReset")
2271 {
2272 bool* pltRst = std::get_if<bool>(&value);
2273 if (pltRst == nullptr)
2274 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002275 std::string errMsg = property + " property invalid";
2276 phosphor::logging::log<phosphor::logging::level::ERR>(
2277 errMsg.c_str());
Jason M. Billsfb957332021-01-28 13:18:46 -08002278 return;
2279 }
2280 pltRstHandler(*pltRst);
2281 }
2282 }
2283}
2284
Zev Weiss584aa132021-09-02 19:21:52 -05002285static void postCompleteHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002286{
Zev Weiss584aa132021-09-02 19:21:52 -05002287 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002288 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002289 sendPowerControlEvent(Event::postCompleteAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002290 osIface->set_property("OperatingSystemState", std::string("Standby"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002291 }
2292 else
2293 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002294 sendPowerControlEvent(Event::postCompleteDeAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002295 osIface->set_property("OperatingSystemState", std::string("Inactive"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002296 }
Zev Weiss584aa132021-09-02 19:21:52 -05002297}
2298
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302299static int loadConfigValues()
2300{
2301 const std::string configFilePath =
2302 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2303 ".json";
2304 std::ifstream configFile(configFilePath.c_str());
2305 if (!configFile.is_open())
2306 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002307 phosphor::logging::log<phosphor::logging::level::ERR>(
2308 "loadConfigValues : Cannot open config path");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302309 return -1;
2310 }
Zev Weiss1aa08b22021-09-15 17:06:20 -05002311 auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302312
Priyatharshan P70120512020-09-16 18:47:20 +05302313 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302314 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002315 phosphor::logging::log<phosphor::logging::level::ERR>(
2316 "Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302317 return -1;
2318 }
Priyatharshan P70120512020-09-16 18:47:20 +05302319 auto gpios = jsonData["gpio_configs"];
2320 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302321
Priyatharshan P70120512020-09-16 18:47:20 +05302322 ConfigData* tempGpioData;
2323
2324 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302325 {
Priyatharshan P70120512020-09-16 18:47:20 +05302326 if (!gpioConfig.contains("Name"))
2327 {
2328 phosphor::logging::log<phosphor::logging::level::ERR>(
2329 "The 'Name' field must be defined in Json file");
2330 return -1;
2331 }
2332
2333 // Iterate through the powersignal map to check if the gpio json config
2334 // entry is valid
2335 std::string gpioName = gpioConfig["Name"];
2336 auto signalMapIter = powerSignalMap.find(gpioName);
2337 if (signalMapIter == powerSignalMap.end())
2338 {
2339 std::string errMsg = "Undefined Name : " + gpioName;
2340 phosphor::logging::log<phosphor::logging::level::ERR>(
2341 errMsg.c_str());
2342 return -1;
2343 }
2344
2345 // assign the power signal name to the corresponding structure reference
2346 // from map then fillup the structure with coressponding json config
2347 // value
2348 tempGpioData = signalMapIter->second;
2349 tempGpioData->name = gpioName;
2350
2351 if (!gpioConfig.contains("Type"))
2352 {
2353 phosphor::logging::log<phosphor::logging::level::ERR>(
2354 "The \'Type\' field must be defined in Json file");
2355 return -1;
2356 }
2357
2358 std::string signalType = gpioConfig["Type"];
2359 if (signalType == "GPIO")
2360 {
2361 tempGpioData->type = ConfigType::GPIO;
2362 }
2363 else if (signalType == "DBUS")
2364 {
2365 tempGpioData->type = ConfigType::DBUS;
2366 }
2367 else
2368 {
2369 std::string errMsg = "Undefined Type : " + signalType;
2370 phosphor::logging::log<phosphor::logging::level::ERR>(
2371 errMsg.c_str());
2372 return -1;
2373 }
2374
2375 if (tempGpioData->type == ConfigType::GPIO)
2376 {
2377 if (gpioConfig.contains("LineName"))
2378 {
2379 tempGpioData->lineName = gpioConfig["LineName"];
2380 }
2381 else
2382 {
2383 phosphor::logging::log<phosphor::logging::level::ERR>(
2384 "The \'LineName\' field must be defined for GPIO "
2385 "configuration");
2386 return -1;
2387 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002388 if (gpioConfig.contains("Polarity"))
2389 {
2390 std::string polarity = gpioConfig["Polarity"];
2391 if (polarity == "ActiveLow")
2392 {
2393 tempGpioData->polarity = false;
2394 }
2395 else if (polarity == "ActiveHigh")
2396 {
2397 tempGpioData->polarity = true;
2398 }
2399 else
2400 {
2401 std::string errMsg =
2402 "Polarity defined but not properly setup. Please "
2403 "only ActiveHigh or ActiveLow. Currently set to " +
2404 polarity;
2405 phosphor::logging::log<phosphor::logging::level::ERR>(
2406 errMsg.c_str());
2407 return -1;
2408 }
2409 }
2410 else
2411 {
2412 std::string errMsg =
2413 "Polarity field not found for " + tempGpioData->lineName;
2414 phosphor::logging::log<phosphor::logging::level::ERR>(
2415 errMsg.c_str());
2416 return -1;
2417 }
Priyatharshan P70120512020-09-16 18:47:20 +05302418 }
2419 else
2420 {
2421 // if dbus based gpio config is defined read and update the dbus
2422 // params corresponding to the gpio config instance
2423 for (auto& [key, dbusParamName] : dbusParams)
2424 {
2425 if (!gpios.contains(dbusParamName))
2426 {
2427 std::string errMsg =
2428 "The " + dbusParamName +
2429 "field must be defined for Dbus configuration ";
2430 phosphor::logging::log<phosphor::logging::level::ERR>(
2431 errMsg.c_str());
2432 return -1;
2433 }
2434 }
2435 tempGpioData->dbusName = gpios[dbusParams[DbusConfigType::name]];
2436 tempGpioData->path = gpios[dbusParams[DbusConfigType::path]];
2437 tempGpioData->interface =
2438 gpios[dbusParams[DbusConfigType::interface]];
2439 tempGpioData->lineName =
2440 gpios[dbusParams[DbusConfigType::property]];
2441 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302442 }
2443
Priyatharshan P70120512020-09-16 18:47:20 +05302444 // read and store the timer values from json config to Timer Map
2445 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302446 {
Priyatharshan P70120512020-09-16 18:47:20 +05302447 if (timers.contains(key.c_str()))
2448 {
2449 timerValue = timers[key.c_str()];
2450 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302451 }
2452
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302453 return 0;
2454}
Zev Weissa8f116a2021-09-01 21:08:30 -05002455
2456static bool getDbusMsgGPIOState(sdbusplus::message::message& msg,
2457 const std::string& lineName, bool& value)
2458{
2459 std::string thresholdInterface;
2460 std::string event;
2461 boost::container::flat_map<std::string, std::variant<bool>>
2462 propertiesChanged;
2463 try
2464 {
2465 msg.read(thresholdInterface, propertiesChanged);
2466 if (propertiesChanged.empty())
2467 {
2468 return false;
2469 }
2470
2471 event = propertiesChanged.begin()->first;
2472 if (event.empty() || event != lineName)
2473 {
2474 return false;
2475 }
2476
2477 value = std::get<bool>(propertiesChanged.begin()->second);
2478 return true;
2479 }
2480 catch (std::exception& e)
2481 {
2482 std::string logmsg =
2483 "exception while reading dbus property: " + lineName;
2484 phosphor::logging::log<phosphor::logging::level::ERR>(logmsg.c_str());
2485 return false;
2486 }
2487}
2488
2489static sdbusplus::bus::match::match
2490 dbusGPIOMatcher(const ConfigData& cfg, std::function<void(bool)> onMatch)
2491{
2492 auto pulseEventMatcherCallback =
2493 [&cfg, onMatch](sdbusplus::message::message& msg) {
2494 bool value = false;
2495 if (!getDbusMsgGPIOState(msg, cfg.lineName, value))
2496 {
2497 return;
2498 }
2499 onMatch(value);
2500 };
2501
2502 return sdbusplus::bus::match::match(
2503 static_cast<sdbusplus::bus::bus&>(*conn),
2504 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2505 "PropertiesChanged',arg0='" +
2506 cfg.dbusName + "'",
2507 std::move(pulseEventMatcherCallback));
2508}
2509
Priyatharshan P70120512020-09-16 18:47:20 +05302510int getProperty(ConfigData& configData)
2511{
2512 auto method = conn->new_method_call(
2513 configData.dbusName.c_str(), configData.path.c_str(),
2514 "org.freedesktop.DBus.Properties", "Get");
2515 method.append(configData.interface.c_str(), configData.lineName.c_str());
2516
2517 auto reply = conn->call(method);
2518 if (reply.is_method_error())
2519 {
2520 phosphor::logging::log<phosphor::logging::level::ERR>(
2521 "Error reading from Bus");
2522 return -1;
2523 }
2524 std::variant<int> resp;
2525 reply.read(resp);
2526 auto respValue = std::get_if<int>(&resp);
2527 if (!respValue)
2528 {
2529 phosphor::logging::log<phosphor::logging::level::ERR>(
2530 "Error reading response");
2531 return -1;
2532 }
2533 return (*respValue);
2534}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002535} // namespace power_control
2536
2537int main(int argc, char* argv[])
2538{
Lei YU92caa4c2021-02-23 16:59:25 +08002539 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05302540
2541 if (argc > 1)
2542 {
2543 node = argv[1];
2544 }
2545 std::string infoMsg =
2546 "Start Chassis power control service for host : " + node;
2547 phosphor::logging::log<phosphor::logging::level::INFO>(infoMsg.c_str());
2548
Lei YU92caa4c2021-02-23 16:59:25 +08002549 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002550
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302551 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08002552 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302553 {
Lei YU92caa4c2021-02-23 16:59:25 +08002554 std::string errMsg = "Host" + node + ": " + "Error in Parsing...";
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002555 phosphor::logging::log<phosphor::logging::level::ERR>(errMsg.c_str());
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302556 }
Naveen Mosesec972d82021-07-16 21:19:23 +05302557 /* Currently for single host based systems additional busname is added
2558 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
2559 Going forward for single hosts the old bus name without zero numbering
2560 will be removed when all other applications adapted to the
2561 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
2562
2563 if (node == "0")
2564 {
2565 // Request all the dbus names
2566 conn->request_name(hostDbusName.c_str());
2567 conn->request_name(chassisDbusName.c_str());
2568 conn->request_name(osDbusName.c_str());
2569 conn->request_name(buttonDbusName.c_str());
2570 conn->request_name(nmiDbusName.c_str());
2571 conn->request_name(rstCauseDbusName.c_str());
2572 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302573
Zev Weissc4005bd2021-09-01 22:30:23 -05002574 hostDbusName += node;
2575 chassisDbusName += node;
2576 osDbusName += node;
2577 buttonDbusName += node;
2578 nmiDbusName += node;
2579 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002580
Priyatharshan P70120512020-09-16 18:47:20 +05302581 // Request all the dbus names
2582 conn->request_name(hostDbusName.c_str());
2583 conn->request_name(chassisDbusName.c_str());
2584 conn->request_name(osDbusName.c_str());
2585 conn->request_name(buttonDbusName.c_str());
2586 conn->request_name(nmiDbusName.c_str());
2587 conn->request_name(rstCauseDbusName.c_str());
2588
2589 if (sioPwrGoodConfig.lineName.empty() ||
2590 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05302591 {
Lei YU92caa4c2021-02-23 16:59:25 +08002592 sioEnabled = false;
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002593 phosphor::logging::log<phosphor::logging::level::INFO>(
2594 "SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05302595 }
2596
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002597 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302598 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002599 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002600 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302601 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302602 {
2603 return -1;
2604 }
2605 }
Priyatharshan P70120512020-09-16 18:47:20 +05302606 else if (powerOkConfig.type == ConfigType::DBUS)
2607 {
2608
2609 static sdbusplus::bus::match::match powerOkEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002610 power_control::dbusGPIOMatcher(powerOkConfig, psPowerOKHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302611 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302612 else
2613 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002614 phosphor::logging::log<phosphor::logging::level::ERR>(
2615 "PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002616 return -1;
2617 }
2618
Lei YU92caa4c2021-02-23 16:59:25 +08002619 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002620 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05302621 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302622 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302623 {
Priyatharshan P70120512020-09-16 18:47:20 +05302624 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002625 sioPowerGoodHandler, sioPowerGoodLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302626 sioPowerGoodEvent))
2627 {
2628 return -1;
2629 }
2630 }
2631 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
2632 {
2633 static sdbusplus::bus::match::match sioPwrGoodEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002634 power_control::dbusGPIOMatcher(sioPwrGoodConfig,
2635 sioPowerGoodHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302636 }
2637 else
2638 {
2639 phosphor::logging::log<phosphor::logging::level::ERR>(
2640 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302641 return -1;
2642 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002643
Priyatharshan P19c47a32020-08-12 18:16:43 +05302644 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302645 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302646 {
Priyatharshan P70120512020-09-16 18:47:20 +05302647 if (!requestGPIOEvents(sioOnControlConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002648 sioOnControlHandler, sioOnControlLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302649 sioOnControlEvent))
2650 {
2651 return -1;
2652 }
2653 }
2654 else if (sioOnControlConfig.type == ConfigType::DBUS)
2655 {
2656 static sdbusplus::bus::match::match sioOnControlEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002657 power_control::dbusGPIOMatcher(sioOnControlConfig,
2658 sioOnControlHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302659 }
2660 else
2661 {
2662 phosphor::logging::log<phosphor::logging::level::ERR>(
2663 "sioOnControl name should be configured from json"
2664 "config file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302665 return -1;
2666 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002667
Priyatharshan P19c47a32020-08-12 18:16:43 +05302668 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302669 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302670 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002671 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
Priyatharshan P70120512020-09-16 18:47:20 +05302672 sioS5Line, sioS5Event))
2673 {
2674 return -1;
2675 }
2676 }
2677 else if (sioS5Config.type == ConfigType::DBUS)
2678 {
2679 static sdbusplus::bus::match::match sioS5EventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002680 power_control::dbusGPIOMatcher(sioS5Config, sioS5Handler);
Priyatharshan P70120512020-09-16 18:47:20 +05302681 }
2682 else
2683 {
2684 phosphor::logging::log<phosphor::logging::level::ERR>(
2685 "sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302686 return -1;
2687 }
2688 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002689
2690 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302691 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002692 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002693 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
2694 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302695 {
2696 return -1;
2697 }
2698 }
Priyatharshan P70120512020-09-16 18:47:20 +05302699 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302700 {
Priyatharshan P70120512020-09-16 18:47:20 +05302701 static sdbusplus::bus::match::match powerButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002702 power_control::dbusGPIOMatcher(powerButtonConfig,
2703 powerButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002704 }
2705
2706 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302707 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002708 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002709 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
2710 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302711 {
2712 return -1;
2713 }
2714 }
Priyatharshan P70120512020-09-16 18:47:20 +05302715 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302716 {
Priyatharshan P70120512020-09-16 18:47:20 +05302717 static sdbusplus::bus::match::match resetButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002718 power_control::dbusGPIOMatcher(resetButtonConfig,
2719 resetButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002720 }
2721
2722 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302723 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302724 {
Priyatharshan P70120512020-09-16 18:47:20 +05302725 if (!nmiButtonConfig.lineName.empty())
2726 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002727 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302728 nmiButtonLine, nmiButtonEvent);
2729 }
2730 }
2731 else if (nmiButtonConfig.type == ConfigType::DBUS)
2732 {
2733 static sdbusplus::bus::match::match nmiButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002734 power_control::dbusGPIOMatcher(nmiButtonConfig, nmiButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302735 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002736
2737 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302738 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302739 {
Priyatharshan P70120512020-09-16 18:47:20 +05302740 if (!idButtonConfig.lineName.empty())
2741 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002742 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302743 idButtonLine, idButtonEvent);
2744 }
2745 }
2746 else if (idButtonConfig.type == ConfigType::DBUS)
2747 {
2748 static sdbusplus::bus::match::match idButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002749 power_control::dbusGPIOMatcher(idButtonConfig, idButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302750 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002751
Jason M. Billsfb957332021-01-28 13:18:46 -08002752#ifdef USE_PLT_RST
2753 sdbusplus::bus::match::match pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08002754 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08002755 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2756 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08002757 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08002758#endif
2759
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002760 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302761 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002762 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002763 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
2764 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302765 {
2766 return -1;
2767 }
2768 }
Priyatharshan P70120512020-09-16 18:47:20 +05302769 else if (postCompleteConfig.type == ConfigType::DBUS)
2770 {
2771 static sdbusplus::bus::match::match postCompleteEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002772 power_control::dbusGPIOMatcher(postCompleteConfig,
2773 postCompleteHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302774 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302775 else
2776 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002777 phosphor::logging::log<phosphor::logging::level::ERR>(
2778 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002779 return -1;
2780 }
2781
2782 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05302783 if (!nmiOutConfig.lineName.empty())
2784 {
2785 setGPIOOutput(nmiOutConfig.lineName, 0, nmiOutLine);
2786 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002787
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002788 // Initialize POWER_OUT and RESET_OUT GPIO.
2789 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05302790 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002791 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002792 if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
2793 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302794 {
2795 return -1;
2796 }
2797 }
2798 else
2799 {
2800 phosphor::logging::log<phosphor::logging::level::ERR>(
2801 "powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002802 return -1;
2803 }
2804
Priyatharshan P70120512020-09-16 18:47:20 +05302805 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002806 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002807 if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
2808 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302809 {
2810 return -1;
2811 }
2812 }
2813 else
2814 {
2815 phosphor::logging::log<phosphor::logging::level::ERR>(
2816 "ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002817 return -1;
2818 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002819 // Release line
2820 line.reset();
2821
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002822 // Initialize the power state
Lei YU92caa4c2021-02-23 16:59:25 +08002823 powerState = PowerState::off;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002824 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05302825
2826 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002827 {
Jean-Marie Verdun61b4a5b2021-09-19 08:53:28 -04002828 if (psPowerOKLine.get_value() > 0 ||
Lei YUa37c2472021-09-26 15:57:12 +08002829 (sioEnabled &&
2830 (sioPowerGoodLine.get_value() == sioPwrGoodConfig.polarity)))
Priyatharshan P70120512020-09-16 18:47:20 +05302831 {
2832 powerState = PowerState::on;
2833 }
2834 }
2835 else
2836 {
2837 if (getProperty(powerOkConfig))
2838 {
2839 powerState = PowerState::on;
2840 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002841 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002842 // Initialize the power state storage
Lei YU92caa4c2021-02-23 16:59:25 +08002843 if (initializePowerStateStorage() < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002844 {
2845 return -1;
2846 }
2847
2848 // Check if we need to start the Power Restore policy
Lei YU92caa4c2021-02-23 16:59:25 +08002849 powerRestorePolicyCheck();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002850
Lei YU92caa4c2021-02-23 16:59:25 +08002851 if (nmiOutLine)
2852 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002853
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002854 phosphor::logging::log<phosphor::logging::level::INFO>(
2855 "Initializing power state. ");
Lei YU92caa4c2021-02-23 16:59:25 +08002856 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002857
2858 // Power Control Service
2859 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002860 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002861
2862 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05302863 hostIface =
2864 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
2865 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002866 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08002867 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002868 "RequestedHostTransition",
2869 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2870 [](const std::string& requested, std::string& resp) {
2871 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2872 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002873 // if power button is masked, ignore this
2874 if (!powerButtonMask)
2875 {
2876 sendPowerControlEvent(Event::gracefulPowerOffRequest);
2877 addRestartCause(RestartCause::command);
2878 }
2879 else
2880 {
2881 phosphor::logging::log<phosphor::logging::level::INFO>(
2882 "Power Button Masked.");
2883 throw std::invalid_argument("Transition Request Masked");
2884 return 0;
2885 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002886 }
2887 else if (requested ==
2888 "xyz.openbmc_project.State.Host.Transition.On")
2889 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002890 // if power button is masked, ignore this
2891 if (!powerButtonMask)
2892 {
2893 sendPowerControlEvent(Event::powerOnRequest);
2894 addRestartCause(RestartCause::command);
2895 }
2896 else
2897 {
2898 phosphor::logging::log<phosphor::logging::level::INFO>(
2899 "Power Button Masked.");
2900 throw std::invalid_argument("Transition Request Masked");
2901 return 0;
2902 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002903 }
2904 else if (requested ==
2905 "xyz.openbmc_project.State.Host.Transition.Reboot")
2906 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002907 // if power button is masked, ignore this
2908 if (!powerButtonMask)
2909 {
2910 sendPowerControlEvent(Event::powerCycleRequest);
2911 addRestartCause(RestartCause::command);
2912 }
2913 else
2914 {
2915 phosphor::logging::log<phosphor::logging::level::INFO>(
2916 "Power Button Masked.");
2917 throw std::invalid_argument("Transition Request Masked");
2918 return 0;
2919 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002920 }
2921 else if (requested == "xyz.openbmc_project.State.Host.Transition."
2922 "GracefulWarmReboot")
2923 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002924 // if reset button is masked, ignore this
2925 if (!resetButtonMask)
2926 {
2927 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
2928 addRestartCause(RestartCause::command);
2929 }
2930 else
2931 {
2932 phosphor::logging::log<phosphor::logging::level::INFO>(
2933 "Reset Button Masked.");
2934 throw std::invalid_argument("Transition Request Masked");
2935 return 0;
2936 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002937 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002938 else if (requested == "xyz.openbmc_project.State.Host.Transition."
2939 "ForceWarmReboot")
2940 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002941 // if reset button is masked, ignore this
2942 if (!resetButtonMask)
2943 {
2944 sendPowerControlEvent(Event::resetRequest);
2945 addRestartCause(RestartCause::command);
2946 }
2947 else
2948 {
2949 phosphor::logging::log<phosphor::logging::level::INFO>(
2950 "Reset Button Masked.");
2951 throw std::invalid_argument("Transition Request Masked");
2952 return 0;
2953 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002954 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002955 else
2956 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002957 phosphor::logging::log<phosphor::logging::level::ERR>(
2958 "Unrecognized host state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002959 throw std::invalid_argument("Unrecognized Transition Request");
2960 return 0;
2961 }
2962 resp = requested;
2963 return 1;
2964 });
Lei YU92caa4c2021-02-23 16:59:25 +08002965 hostIface->register_property("CurrentHostState",
2966 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002967
Lei YU92caa4c2021-02-23 16:59:25 +08002968 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002969
2970 // Chassis Control Service
2971 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002972 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002973
2974 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002975 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05302976 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002977 "xyz.openbmc_project.State.Chassis");
2978
Lei YU92caa4c2021-02-23 16:59:25 +08002979 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002980 "RequestedPowerTransition",
2981 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
2982 [](const std::string& requested, std::string& resp) {
2983 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
2984 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002985 // if power button is masked, ignore this
2986 if (!powerButtonMask)
2987 {
2988 sendPowerControlEvent(Event::powerOffRequest);
2989 addRestartCause(RestartCause::command);
2990 }
2991 else
2992 {
2993 phosphor::logging::log<phosphor::logging::level::INFO>(
2994 "Power Button Masked.");
2995 throw std::invalid_argument("Transition Request Masked");
2996 return 0;
2997 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002998 }
2999 else if (requested ==
3000 "xyz.openbmc_project.State.Chassis.Transition.On")
3001 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003002 // if power button is masked, ignore this
3003 if (!powerButtonMask)
3004 {
3005 sendPowerControlEvent(Event::powerOnRequest);
3006 addRestartCause(RestartCause::command);
3007 }
3008 else
3009 {
3010 phosphor::logging::log<phosphor::logging::level::INFO>(
3011 "Power Button Masked.");
3012 throw std::invalid_argument("Transition Request Masked");
3013 return 0;
3014 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003015 }
3016 else if (requested ==
3017 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3018 {
Vernon Mauery2a269432021-07-14 10:00:21 -07003019 // if power button is masked, ignore this
3020 if (!powerButtonMask)
3021 {
3022 sendPowerControlEvent(Event::powerCycleRequest);
3023 addRestartCause(RestartCause::command);
3024 }
3025 else
3026 {
3027 phosphor::logging::log<phosphor::logging::level::INFO>(
3028 "Power Button Masked.");
3029 throw std::invalid_argument("Transition Request Masked");
3030 return 0;
3031 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003032 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003033 else
3034 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003035 phosphor::logging::log<phosphor::logging::level::ERR>(
3036 "Unrecognized chassis state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003037 throw std::invalid_argument("Unrecognized Transition Request");
3038 return 0;
3039 }
3040 resp = requested;
3041 return 1;
3042 });
Lei YU92caa4c2021-02-23 16:59:25 +08003043 chassisIface->register_property("CurrentPowerState",
3044 std::string(getChassisState(powerState)));
3045 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003046
Lei YU92caa4c2021-02-23 16:59:25 +08003047 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003048
Vijay Khemka04175c22020-10-09 14:28:11 -07003049#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003050 // Chassis System Service
3051 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003052 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003053
3054 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003055 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003056 "/xyz/openbmc_project/state/chassis_system0",
3057 "xyz.openbmc_project.State.Chassis");
3058
Lei YU92caa4c2021-02-23 16:59:25 +08003059 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003060 "RequestedPowerTransition",
3061 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3062 [](const std::string& requested, std::string& resp) {
3063 if (requested ==
3064 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
3065 {
Lei YU92caa4c2021-02-23 16:59:25 +08003066 systemReset();
3067 addRestartCause(RestartCause::command);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003068 }
3069 else
3070 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003071 phosphor::logging::log<phosphor::logging::level::ERR>(
3072 "Unrecognized chassis system state transition request.");
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003073 throw std::invalid_argument("Unrecognized Transition Request");
3074 return 0;
3075 }
3076 resp = requested;
3077 return 1;
3078 });
Lei YU92caa4c2021-02-23 16:59:25 +08003079 chassisSysIface->register_property(
3080 "CurrentPowerState", std::string(getChassisState(powerState)));
3081 chassisSysIface->register_property("LastStateChangeTime",
3082 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003083
Lei YU92caa4c2021-02-23 16:59:25 +08003084 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003085
Naveen Moses117c34e2021-05-26 20:10:51 +05303086 if (!slotPowerConfig.lineName.empty())
3087 {
3088 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3089 {
3090 return -1;
3091 }
3092
3093 slotPowerState = SlotPowerState::off;
3094 if (slotPowerLine.get_value() > 0)
3095 {
3096 slotPowerState = SlotPowerState::on;
3097 }
3098
3099 chassisSlotIface = chassisSysServer.add_interface(
3100 "/xyz/openbmc_project/state/chassis_system" + node,
3101 "xyz.openbmc_project.State.Chassis");
3102 chassisSlotIface->register_property(
3103 "RequestedPowerTransition",
3104 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3105 [](const std::string& requested, std::string& resp) {
3106 if (requested ==
3107 "xyz.openbmc_project.State.Chassis.Transition.On")
3108 {
3109 slotPowerOn();
3110 }
3111 else if (requested ==
3112 "xyz.openbmc_project.State.Chassis.Transition.Off")
3113 {
3114 slotPowerOff();
3115 }
3116 else if (requested == "xyz.openbmc_project.State.Chassis."
3117 "Transition.PowerCycle")
3118 {
3119 slotPowerCycle();
3120 }
3121 else
3122 {
3123 phosphor::logging::log<phosphor::logging::level::ERR>(
3124 "Unrecognized chassis system state transition "
3125 "request.\n");
3126 throw std::invalid_argument(
3127 "Unrecognized Transition Request");
3128 return 0;
3129 }
3130 resp = requested;
3131 return 1;
3132 });
3133 chassisSlotIface->register_property(
3134 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3135 chassisSlotIface->register_property("LastStateChangeTime",
3136 getCurrentTimeMs());
3137 chassisSlotIface->initialize();
3138 }
3139#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003140 // Buttons Service
3141 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003142 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003143
Priyatharshan P70120512020-09-16 18:47:20 +05303144 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003145 {
Priyatharshan P70120512020-09-16 18:47:20 +05303146 // Power Button Interface
3147 power_control::powerButtonIface = buttonsServer.add_interface(
3148 "/xyz/openbmc_project/chassis/buttons/power",
3149 "xyz.openbmc_project.Chassis.Buttons");
3150
3151 powerButtonIface->register_property(
3152 "ButtonMasked", false, [](const bool requested, bool& current) {
3153 if (requested)
3154 {
3155 if (powerButtonMask)
3156 {
3157 return 1;
3158 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003159 if (!setGPIOOutput(powerOutConfig.lineName,
3160 !powerOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303161 powerButtonMask))
3162 {
3163 throw std::runtime_error("Failed to request GPIO");
3164 return 0;
3165 }
3166 phosphor::logging::log<phosphor::logging::level::INFO>(
3167 "Power Button Masked.");
3168 }
3169 else
3170 {
3171 if (!powerButtonMask)
3172 {
3173 return 1;
3174 }
3175 phosphor::logging::log<phosphor::logging::level::INFO>(
3176 "Power Button Un-masked");
3177 powerButtonMask.reset();
3178 }
3179 // Update the mask setting
3180 current = requested;
3181 return 1;
3182 });
3183
3184 // Check power button state
3185 bool powerButtonPressed;
3186 if (powerButtonConfig.type == ConfigType::GPIO)
3187 {
3188 powerButtonPressed = powerButtonLine.get_value() == 0;
3189 }
3190 else
3191 {
3192 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3193 }
3194
3195 powerButtonIface->register_property("ButtonPressed",
3196 powerButtonPressed);
3197
3198 powerButtonIface->initialize();
3199 }
3200
3201 if (!resetButtonConfig.lineName.empty())
3202 {
3203 // Reset Button Interface
3204
Lei YU92caa4c2021-02-23 16:59:25 +08003205 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003206 "/xyz/openbmc_project/chassis/buttons/reset",
3207 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003208
Lei YU92caa4c2021-02-23 16:59:25 +08003209 resetButtonIface->register_property(
John Wang6c090072020-09-30 13:32:16 +08003210 "ButtonMasked", false, [](const bool requested, bool& current) {
3211 if (requested)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003212 {
Lei YU92caa4c2021-02-23 16:59:25 +08003213 if (resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003214 {
3215 return 1;
3216 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003217 if (!setGPIOOutput(resetOutConfig.lineName,
3218 !resetOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303219 resetButtonMask))
John Wang6c090072020-09-30 13:32:16 +08003220 {
3221 throw std::runtime_error("Failed to request GPIO");
3222 return 0;
3223 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003224 phosphor::logging::log<phosphor::logging::level::INFO>(
3225 "Reset Button Masked.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003226 }
John Wang6c090072020-09-30 13:32:16 +08003227 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003228 {
Lei YU92caa4c2021-02-23 16:59:25 +08003229 if (!resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003230 {
3231 return 1;
3232 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003233 phosphor::logging::log<phosphor::logging::level::INFO>(
3234 "Reset Button Un-masked");
Lei YU92caa4c2021-02-23 16:59:25 +08003235 resetButtonMask.reset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003236 }
John Wang6c090072020-09-30 13:32:16 +08003237 // Update the mask setting
3238 current = requested;
3239 return 1;
3240 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003241
John Wang6c090072020-09-30 13:32:16 +08003242 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303243 bool resetButtonPressed;
3244 if (resetButtonConfig.type == ConfigType::GPIO)
3245 {
3246 resetButtonPressed = resetButtonLine.get_value() == 0;
3247 }
3248 else
3249 {
3250 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3251 }
3252
Lei YU92caa4c2021-02-23 16:59:25 +08003253 resetButtonIface->register_property("ButtonPressed",
3254 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003255
Lei YU92caa4c2021-02-23 16:59:25 +08003256 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003257 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003258
Lei YU92caa4c2021-02-23 16:59:25 +08003259 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003260 {
3261 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003262 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003263 "/xyz/openbmc_project/chassis/buttons/nmi",
3264 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003265
Lei YU92caa4c2021-02-23 16:59:25 +08003266 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003267 "ButtonMasked", false, [](const bool requested, bool& current) {
Lei YU92caa4c2021-02-23 16:59:25 +08003268 if (nmiButtonMasked == requested)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003269 {
3270 // NMI button mask is already set as requested, so no change
3271 return 1;
3272 }
3273 if (requested)
3274 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003275 phosphor::logging::log<phosphor::logging::level::INFO>(
3276 "NMI Button Masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003277 nmiButtonMasked = true;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003278 }
3279 else
3280 {
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003281 phosphor::logging::log<phosphor::logging::level::INFO>(
3282 "NMI Button Un-masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003283 nmiButtonMasked = false;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003284 }
3285 // Update the mask setting
Lei YU92caa4c2021-02-23 16:59:25 +08003286 current = nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003287 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003288 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003289
Vijay Khemka33a532d2019-11-14 16:50:35 -08003290 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303291 bool nmiButtonPressed;
3292 if (nmiButtonConfig.type == ConfigType::GPIO)
3293 {
3294 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3295 }
3296 else
3297 {
3298 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3299 }
3300
Lei YU92caa4c2021-02-23 16:59:25 +08003301 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003302
Lei YU92caa4c2021-02-23 16:59:25 +08003303 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003304 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003305
Lei YU92caa4c2021-02-23 16:59:25 +08003306 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003307 {
3308 // NMI out Service
3309 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003310 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003311
Vijay Khemka33a532d2019-11-14 16:50:35 -08003312 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303313 nmiOutIface = nmiOutServer.add_interface(
3314 "/xyz/openbmc_project/control/host" + node + "/nmi",
3315 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003316 nmiOutIface->register_method("NMI", nmiReset);
3317 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003318 }
Chen Yugang174ec662019-08-19 19:58:49 +08003319
Lei YU92caa4c2021-02-23 16:59:25 +08003320 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003321 {
3322 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003323 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003324 "/xyz/openbmc_project/chassis/buttons/id",
3325 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003326
Vijay Khemka33a532d2019-11-14 16:50:35 -08003327 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303328 bool idButtonPressed;
3329 if (idButtonConfig.type == ConfigType::GPIO)
3330 {
3331 idButtonPressed = idButtonLine.get_value() == 0;
3332 }
3333 else
3334 {
3335 idButtonPressed = getProperty(idButtonConfig) == 0;
3336 }
3337
Lei YU92caa4c2021-02-23 16:59:25 +08003338 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003339
Lei YU92caa4c2021-02-23 16:59:25 +08003340 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003341 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003342
3343 // OS State Service
3344 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003345 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003346
3347 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003348 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003349 "/xyz/openbmc_project/state/os",
3350 "xyz.openbmc_project.State.OperatingSystem.Status");
3351
3352 // Get the initial OS state based on POST complete
3353 // 0: Asserted, OS state is "Standby" (ready to boot)
3354 // 1: De-Asserted, OS state is "Inactive"
Priyatharshan P70120512020-09-16 18:47:20 +05303355 std::string osState;
3356 if (postCompleteConfig.type == ConfigType::GPIO)
3357 {
3358 osState = postCompleteLine.get_value() > 0 ? "Inactive" : "Standby";
3359 }
3360 else
3361 {
3362 osState = getProperty(postCompleteConfig) > 0 ? "Inactive" : "Standby";
3363 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003364
Lei YU92caa4c2021-02-23 16:59:25 +08003365 osIface->register_property("OperatingSystemState", std::string(osState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003366
Lei YU92caa4c2021-02-23 16:59:25 +08003367 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003368
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003369 // Restart Cause Service
3370 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003371 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003372
3373 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003374 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303375 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003376 "xyz.openbmc_project.Control.Host.RestartCause");
3377
Lei YU92caa4c2021-02-23 16:59:25 +08003378 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003379 "RestartCause",
3380 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3381
Lei YU92caa4c2021-02-23 16:59:25 +08003382 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003383 "RequestedRestartCause",
3384 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3385 [](const std::string& requested, std::string& resp) {
3386 if (requested ==
3387 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3388 {
Lei YU92caa4c2021-02-23 16:59:25 +08003389 addRestartCause(RestartCause::watchdog);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003390 }
3391 else
3392 {
3393 throw std::invalid_argument(
3394 "Unrecognized RestartCause Request");
3395 return 0;
3396 }
3397
Jason M. Bills41a49aa2021-03-03 16:03:25 -08003398 std::string logMsg = "RestartCause requested: " + requested;
3399 phosphor::logging::log<phosphor::logging::level::INFO>(
3400 logMsg.c_str());
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003401 resp = requested;
3402 return 1;
3403 });
3404
Lei YU92caa4c2021-02-23 16:59:25 +08003405 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003406
Lei YU92caa4c2021-02-23 16:59:25 +08003407 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003408
Lei YU92caa4c2021-02-23 16:59:25 +08003409 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003410
3411 return 0;
3412}