blob: fbe126630b46c24e8eff856b7ebd43aeca9ac417 [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*/
Ed Tanousf61ca6f2019-08-15 15:09:05 -070016#include <sys/sysinfo.h>
17#include <systemd/sd-journal.h>
18
Jason M. Billse63dea02020-08-27 12:07:35 -070019#include <boost/asio/io_service.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070020#include <boost/asio/posix/stream_descriptor.hpp>
Jason M. Billse63dea02020-08-27 12:07:35 -070021#include <boost/asio/steady_timer.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070022#include <boost/container/flat_map.hpp>
Jason M. Bills7d4aaac2019-09-19 14:03:44 -070023#include <boost/container/flat_set.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070024#include <gpiod.hpp>
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053025#include <nlohmann/json.hpp>
Jason M. Billsc46ebb42021-11-10 11:41:31 -080026#include <phosphor-logging/lg2.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070027#include <sdbusplus/asio/object_server.hpp>
Vijay Khemka2b6f4422020-05-29 11:13:23 -070028
29#include <filesystem>
30#include <fstream>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070031#include <string_view>
32
33namespace power_control
34{
35static boost::asio::io_service io;
36std::shared_ptr<sdbusplus::asio::connection> conn;
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053037
38static std::string node = "0";
39
Priyatharshan P70120512020-09-16 18:47:20 +053040enum class DbusConfigType
41{
42 name = 1,
43 path,
44 interface,
45 property
46};
47boost::container::flat_map<DbusConfigType, std::string> dbusParams = {
48 {DbusConfigType::name, "DbusName"},
49 {DbusConfigType::path, "Path"},
50 {DbusConfigType::interface, "Interface"},
51 {DbusConfigType::property, "Property"}};
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053052
Priyatharshan P70120512020-09-16 18:47:20 +053053enum class ConfigType
54{
55 GPIO = 1,
56 DBUS
57};
58
59struct ConfigData
60{
61 std::string name;
62 std::string lineName;
63 std::string dbusName;
64 std::string path;
65 std::string interface;
Jean-Marie Verdun50937e72021-08-31 09:15:49 -070066 bool polarity;
Priyatharshan P70120512020-09-16 18:47:20 +053067 ConfigType type;
68};
69
70static ConfigData powerOutConfig;
71static ConfigData powerOkConfig;
72static ConfigData resetOutConfig;
73static ConfigData nmiOutConfig;
74static ConfigData sioPwrGoodConfig;
75static ConfigData sioOnControlConfig;
76static ConfigData sioS5Config;
77static ConfigData postCompleteConfig;
78static ConfigData powerButtonConfig;
79static ConfigData resetButtonConfig;
80static ConfigData idButtonConfig;
81static ConfigData nmiButtonConfig;
Naveen Moses117c34e2021-05-26 20:10:51 +053082static ConfigData slotPowerConfig;
83
Priyatharshan P70120512020-09-16 18:47:20 +053084// map for storing list of gpio parameters whose config are to be read from x86
85// power control json config
86boost::container::flat_map<std::string, ConfigData*> powerSignalMap = {
87 {"PowerOut", &powerOutConfig},
88 {"PowerOk", &powerOkConfig},
89 {"ResetOut", &resetOutConfig},
90 {"NMIOut", &nmiOutConfig},
91 {"SioPowerGood", &sioPwrGoodConfig},
92 {"SioOnControl", &sioOnControlConfig},
93 {"SIOS5", &sioS5Config},
94 {"PostComplete", &postCompleteConfig},
95 {"PowerButton", &powerButtonConfig},
96 {"ResetButton", &resetButtonConfig},
97 {"IdButton", &idButtonConfig},
Naveen Moses117c34e2021-05-26 20:10:51 +053098 {"NMIButton", &nmiButtonConfig},
99 {"SlotPower", &slotPowerConfig}};
Priyatharshan P70120512020-09-16 18:47:20 +0530100
101static std::string hostDbusName = "xyz.openbmc_project.State.Host";
102static std::string chassisDbusName = "xyz.openbmc_project.State.Chassis";
103static std::string osDbusName = "xyz.openbmc_project.State.OperatingSystem";
104static std::string buttonDbusName = "xyz.openbmc_project.Chassis.Buttons";
105static std::string nmiDbusName = "xyz.openbmc_project.Control.Host.NMI";
106static std::string rstCauseDbusName =
107 "xyz.openbmc_project.Control.Host.RestartCause";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700108static std::shared_ptr<sdbusplus::asio::dbus_interface> hostIface;
109static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700110#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -0700111static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSysIface;
Naveen Moses117c34e2021-05-26 20:10:51 +0530112static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSlotIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700113#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700114static std::shared_ptr<sdbusplus::asio::dbus_interface> powerButtonIface;
115static std::shared_ptr<sdbusplus::asio::dbus_interface> resetButtonIface;
116static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiButtonIface;
117static std::shared_ptr<sdbusplus::asio::dbus_interface> osIface;
118static std::shared_ptr<sdbusplus::asio::dbus_interface> idButtonIface;
Chen Yugang174ec662019-08-19 19:58:49 +0800119static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiOutIface;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700120static std::shared_ptr<sdbusplus::asio::dbus_interface> restartCauseIface;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700121
122static gpiod::line powerButtonMask;
123static gpiod::line resetButtonMask;
124static bool nmiButtonMasked = false;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700125
Priyatharshan P70120512020-09-16 18:47:20 +0530126// This map contains all timer values that are to be read from json config
127boost::container::flat_map<std::string, int> TimerMap = {
Jason M. Billsaeefe042021-09-08 14:56:11 -0700128 {"PowerPulseMs", 200},
129 {"ForceOffPulseMs", 15000},
130 {"ResetPulseMs", 500},
131 {"PowerCycleMs", 5000},
132 {"SioPowerGoodWatchdogMs", 1000},
133 {"PsPowerOKWatchdogMs", 8000},
134 {"GracefulPowerOffS", (5 * 60)},
135 {"WarmResetCheckMs", 500},
136 {"PowerOffSaveMs", 7000},
137 {"SlotPowerCycleMs", 200}};
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700138const static std::filesystem::path powerControlDir = "/var/lib/power-control";
139const static constexpr std::string_view powerStateFile = "power-state";
140
141static bool nmiEnabled = true;
Priyatharshan P19c47a32020-08-12 18:16:43 +0530142static bool sioEnabled = true;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700143
144// Timers
145// Time holding GPIOs asserted
146static boost::asio::steady_timer gpioAssertTimer(io);
147// Time between off and on during a power cycle
148static boost::asio::steady_timer powerCycleTimer(io);
149// Time OS gracefully powering off
150static boost::asio::steady_timer gracefulPowerOffTimer(io);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700151// Time the warm reset check
152static boost::asio::steady_timer warmResetCheckTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700153// Time power supply power OK assertion on power-on
154static boost::asio::steady_timer psPowerOKWatchdogTimer(io);
155// Time SIO power good assertion on power-on
156static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io);
157// Time power-off state save for power loss tracking
158static boost::asio::steady_timer powerStateSaveTimer(io);
159// POH timer
160static boost::asio::steady_timer pohCounterTimer(io);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700161// Time when to allow restart cause updates
162static boost::asio::steady_timer restartCauseTimer(io);
Naveen Moses117c34e2021-05-26 20:10:51 +0530163static boost::asio::steady_timer slotPowerCycleTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700164
165// GPIO Lines and Event Descriptors
166static gpiod::line psPowerOKLine;
167static boost::asio::posix::stream_descriptor psPowerOKEvent(io);
168static gpiod::line sioPowerGoodLine;
169static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io);
170static gpiod::line sioOnControlLine;
171static boost::asio::posix::stream_descriptor sioOnControlEvent(io);
172static gpiod::line sioS5Line;
173static boost::asio::posix::stream_descriptor sioS5Event(io);
174static gpiod::line powerButtonLine;
175static boost::asio::posix::stream_descriptor powerButtonEvent(io);
176static gpiod::line resetButtonLine;
177static boost::asio::posix::stream_descriptor resetButtonEvent(io);
178static gpiod::line nmiButtonLine;
179static boost::asio::posix::stream_descriptor nmiButtonEvent(io);
180static gpiod::line idButtonLine;
181static boost::asio::posix::stream_descriptor idButtonEvent(io);
182static gpiod::line postCompleteLine;
183static boost::asio::posix::stream_descriptor postCompleteEvent(io);
184static gpiod::line nmiOutLine;
Naveen Moses117c34e2021-05-26 20:10:51 +0530185static gpiod::line slotPowerLine;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700186
187static constexpr uint8_t beepPowerFail = 8;
188
189static void beep(const uint8_t& beepPriority)
190{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800191 lg2::info("Beep with priority: {BEEP_PRIORITY}", "BEEP_PRIORITY",
192 beepPriority);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700193
194 conn->async_method_call(
195 [](boost::system::error_code ec) {
196 if (ec)
197 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800198 lg2::error(
199 "beep returned error with async_method_call (ec = {ERROR_MSG})",
200 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700201 return;
202 }
203 },
204 "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
205 "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
206}
207
208enum class PowerState
209{
210 on,
211 waitForPSPowerOK,
212 waitForSIOPowerGood,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700213 off,
214 transitionToOff,
215 gracefulTransitionToOff,
216 cycleOff,
217 transitionToCycleOff,
218 gracefulTransitionToCycleOff,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700219 checkForWarmReset,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700220};
221static PowerState powerState;
222static std::string getPowerStateName(PowerState state)
223{
224 switch (state)
225 {
226 case PowerState::on:
227 return "On";
228 break;
229 case PowerState::waitForPSPowerOK:
230 return "Wait for Power Supply Power OK";
231 break;
232 case PowerState::waitForSIOPowerGood:
233 return "Wait for SIO Power Good";
234 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700235 case PowerState::off:
236 return "Off";
237 break;
238 case PowerState::transitionToOff:
239 return "Transition to Off";
240 break;
241 case PowerState::gracefulTransitionToOff:
242 return "Graceful Transition to Off";
243 break;
244 case PowerState::cycleOff:
245 return "Power Cycle Off";
246 break;
247 case PowerState::transitionToCycleOff:
248 return "Transition to Power Cycle Off";
249 break;
250 case PowerState::gracefulTransitionToCycleOff:
251 return "Graceful Transition to Power Cycle Off";
252 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700253 case PowerState::checkForWarmReset:
254 return "Check for Warm Reset";
255 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700256 default:
257 return "unknown state: " + std::to_string(static_cast<int>(state));
258 break;
259 }
260}
261static void logStateTransition(const PowerState state)
262{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800263 lg2::info("Host{HOST}: Moving to \"{STATE}\" state", "HOST", node, "STATE",
264 getPowerStateName(state));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700265}
266
267enum class Event
268{
269 psPowerOKAssert,
270 psPowerOKDeAssert,
271 sioPowerGoodAssert,
272 sioPowerGoodDeAssert,
273 sioS5Assert,
274 sioS5DeAssert,
Jason M. Billsfb957332021-01-28 13:18:46 -0800275 pltRstAssert,
276 pltRstDeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700277 postCompleteAssert,
278 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700279 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700280 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700281 powerCycleTimerExpired,
282 psPowerOKWatchdogTimerExpired,
283 sioPowerGoodWatchdogTimerExpired,
284 gracefulPowerOffTimerExpired,
285 powerOnRequest,
286 powerOffRequest,
287 powerCycleRequest,
288 resetRequest,
289 gracefulPowerOffRequest,
290 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700291 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700292};
293static std::string getEventName(Event event)
294{
295 switch (event)
296 {
297 case Event::psPowerOKAssert:
298 return "power supply power OK assert";
299 break;
300 case Event::psPowerOKDeAssert:
301 return "power supply power OK de-assert";
302 break;
303 case Event::sioPowerGoodAssert:
304 return "SIO power good assert";
305 break;
306 case Event::sioPowerGoodDeAssert:
307 return "SIO power good de-assert";
308 break;
309 case Event::sioS5Assert:
310 return "SIO S5 assert";
311 break;
312 case Event::sioS5DeAssert:
313 return "SIO S5 de-assert";
314 break;
Jason M. Billsfb957332021-01-28 13:18:46 -0800315 case Event::pltRstAssert:
316 return "PLT_RST assert";
317 break;
318 case Event::pltRstDeAssert:
319 return "PLT_RST de-assert";
320 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700321 case Event::postCompleteAssert:
322 return "POST Complete assert";
323 break;
324 case Event::postCompleteDeAssert:
325 return "POST Complete de-assert";
326 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700327 case Event::powerButtonPressed:
328 return "power button pressed";
329 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700330 case Event::resetButtonPressed:
331 return "reset button pressed";
332 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700333 case Event::powerCycleTimerExpired:
334 return "power cycle timer expired";
335 break;
336 case Event::psPowerOKWatchdogTimerExpired:
337 return "power supply power OK watchdog timer expired";
338 break;
339 case Event::sioPowerGoodWatchdogTimerExpired:
340 return "SIO power good watchdog timer expired";
341 break;
342 case Event::gracefulPowerOffTimerExpired:
343 return "graceful power-off timer expired";
344 break;
345 case Event::powerOnRequest:
346 return "power-on request";
347 break;
348 case Event::powerOffRequest:
349 return "power-off request";
350 break;
351 case Event::powerCycleRequest:
352 return "power-cycle request";
353 break;
354 case Event::resetRequest:
355 return "reset request";
356 break;
357 case Event::gracefulPowerOffRequest:
358 return "graceful power-off request";
359 break;
360 case Event::gracefulPowerCycleRequest:
361 return "graceful power-cycle request";
362 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700363 case Event::warmResetDetected:
364 return "warm reset detected";
365 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700366 default:
367 return "unknown event: " + std::to_string(static_cast<int>(event));
368 break;
369 }
370}
371static void logEvent(const std::string_view stateHandler, const Event event)
372{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800373 lg2::info("{STATE_HANDLER}: {EVENT} event received", "STATE_HANDLER",
374 stateHandler, "EVENT", getEventName(event));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700375}
376
377// Power state handlers
378static void powerStateOn(const Event event);
379static void powerStateWaitForPSPowerOK(const Event event);
380static void powerStateWaitForSIOPowerGood(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700381static void powerStateOff(const Event event);
382static void powerStateTransitionToOff(const Event event);
383static void powerStateGracefulTransitionToOff(const Event event);
384static void powerStateCycleOff(const Event event);
385static void powerStateTransitionToCycleOff(const Event event);
386static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700387static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700388
389static std::function<void(const Event)> getPowerStateHandler(PowerState state)
390{
391 switch (state)
392 {
393 case PowerState::on:
394 return powerStateOn;
395 break;
396 case PowerState::waitForPSPowerOK:
397 return powerStateWaitForPSPowerOK;
398 break;
399 case PowerState::waitForSIOPowerGood:
400 return powerStateWaitForSIOPowerGood;
401 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700402 case PowerState::off:
403 return powerStateOff;
404 break;
405 case PowerState::transitionToOff:
406 return powerStateTransitionToOff;
407 break;
408 case PowerState::gracefulTransitionToOff:
409 return powerStateGracefulTransitionToOff;
410 break;
411 case PowerState::cycleOff:
412 return powerStateCycleOff;
413 break;
414 case PowerState::transitionToCycleOff:
415 return powerStateTransitionToCycleOff;
416 break;
417 case PowerState::gracefulTransitionToCycleOff:
418 return powerStateGracefulTransitionToCycleOff;
419 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700420 case PowerState::checkForWarmReset:
421 return powerStateCheckForWarmReset;
422 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700423 default:
Zev Weiss047bcb52020-08-20 21:28:11 +0000424 return nullptr;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700425 break;
426 }
427};
428
429static void sendPowerControlEvent(const Event event)
430{
431 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
432 if (handler == nullptr)
433 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800434 lg2::error("Failed to find handler for power state: {STATE}", "STATE",
435 static_cast<int>(powerState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700436 return;
437 }
438 handler(event);
439}
440
441static uint64_t getCurrentTimeMs()
442{
443 struct timespec time = {};
444
445 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
446 {
447 return 0;
448 }
449 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
450 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
451
452 return currentTimeMs;
453}
454
455static constexpr std::string_view getHostState(const PowerState state)
456{
457 switch (state)
458 {
459 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700460 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700461 case PowerState::gracefulTransitionToCycleOff:
462 return "xyz.openbmc_project.State.Host.HostState.Running";
463 break;
464 case PowerState::waitForPSPowerOK:
465 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700466 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700467 case PowerState::transitionToOff:
468 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700469 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700470 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700471 return "xyz.openbmc_project.State.Host.HostState.Off";
472 break;
473 default:
474 return "";
475 break;
476 }
477};
478static constexpr std::string_view getChassisState(const PowerState state)
479{
480 switch (state)
481 {
482 case PowerState::on:
483 case PowerState::transitionToOff:
484 case PowerState::gracefulTransitionToOff:
485 case PowerState::transitionToCycleOff:
486 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700487 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700488 return "xyz.openbmc_project.State.Chassis.PowerState.On";
489 break;
490 case PowerState::waitForPSPowerOK:
491 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700492 case PowerState::off:
493 case PowerState::cycleOff:
494 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
495 break;
496 default:
497 return "";
498 break;
499 }
500};
Naveen Moses117c34e2021-05-26 20:10:51 +0530501#ifdef CHASSIS_SYSTEM_RESET
502enum class SlotPowerState
503{
504 on,
505 off,
506};
507static SlotPowerState slotPowerState;
508static constexpr std::string_view getSlotState(const SlotPowerState state)
509{
510 switch (state)
511 {
512 case SlotPowerState::on:
513 return "xyz.openbmc_project.State.Chassis.PowerState.On";
514 break;
515 case SlotPowerState::off:
516 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
517 break;
518 default:
519 return "";
520 break;
521 }
522};
523static void setSlotPowerState(const SlotPowerState state)
524{
525 slotPowerState = state;
526 chassisSlotIface->set_property("CurrentPowerState",
527 std::string(getSlotState(slotPowerState)));
528 chassisSlotIface->set_property("LastStateChangeTime", getCurrentTimeMs());
529}
530#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700531static void savePowerState(const PowerState state)
532{
533 powerStateSaveTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -0700534 std::chrono::milliseconds(TimerMap["PowerOffSaveMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700535 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
536 if (ec)
537 {
538 // operation_aborted is expected if timer is canceled before
539 // completion.
540 if (ec != boost::asio::error::operation_aborted)
541 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800542 lg2::error("Power-state save async_wait failed: {ERROR_MSG}",
543 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700544 }
545 return;
546 }
547 std::ofstream powerStateStream(powerControlDir / powerStateFile);
548 powerStateStream << getChassisState(state);
549 });
550}
551static void setPowerState(const PowerState state)
552{
553 powerState = state;
554 logStateTransition(state);
555
556 hostIface->set_property("CurrentHostState",
557 std::string(getHostState(powerState)));
558
559 chassisIface->set_property("CurrentPowerState",
560 std::string(getChassisState(powerState)));
561 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
562
563 // Save the power state for the restore policy
564 savePowerState(state);
565}
566
567enum class RestartCause
568{
569 command,
570 resetButton,
571 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700572 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700573 powerPolicyOn,
574 powerPolicyRestore,
575 softReset,
576};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700577static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700578static std::string getRestartCause(RestartCause cause)
579{
580 switch (cause)
581 {
582 case RestartCause::command:
583 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
584 break;
585 case RestartCause::resetButton:
586 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
587 break;
588 case RestartCause::powerButton:
589 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
590 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700591 case RestartCause::watchdog:
592 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
593 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700594 case RestartCause::powerPolicyOn:
Jason M. Bills418ce112021-09-08 15:15:05 -0700595 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyAlwaysOn";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700596 break;
597 case RestartCause::powerPolicyRestore:
Jason M. Bills418ce112021-09-08 15:15:05 -0700598 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyPreviousState";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700599 break;
600 case RestartCause::softReset:
601 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
602 break;
603 default:
604 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
605 break;
606 }
607}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700608static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700609{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700610 // Add this to the set of causes for this restart
611 causeSet.insert(cause);
612}
613static void clearRestartCause()
614{
615 // Clear the set for the next restart
616 causeSet.clear();
617}
618static void setRestartCauseProperty(const std::string& cause)
619{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800620 lg2::info("RestartCause set to {RESTART_CAUSE}", "RESTART_CAUSE", cause);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700621 restartCauseIface->set_property("RestartCause", cause);
622}
Rashmi RV89f61312020-01-22 15:41:50 +0530623
624static void resetACBootProperty()
625{
626 if ((causeSet.contains(RestartCause::command)) ||
627 (causeSet.contains(RestartCause::softReset)))
628 {
629 conn->async_method_call(
630 [](boost::system::error_code ec) {
631 if (ec)
632 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800633 lg2::error("failed to reset ACBoot property");
Rashmi RV89f61312020-01-22 15:41:50 +0530634 }
635 },
636 "xyz.openbmc_project.Settings",
637 "/xyz/openbmc_project/control/host0/ac_boot",
638 "org.freedesktop.DBus.Properties", "Set",
639 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
640 std::variant<std::string>{"False"});
641 }
642}
643
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700644static void setRestartCause()
645{
646 // Determine the actual restart cause based on the set of causes
647 std::string restartCause =
648 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
649 if (causeSet.contains(RestartCause::watchdog))
650 {
651 restartCause = getRestartCause(RestartCause::watchdog);
652 }
653 else if (causeSet.contains(RestartCause::command))
654 {
655 restartCause = getRestartCause(RestartCause::command);
656 }
657 else if (causeSet.contains(RestartCause::resetButton))
658 {
659 restartCause = getRestartCause(RestartCause::resetButton);
660 }
661 else if (causeSet.contains(RestartCause::powerButton))
662 {
663 restartCause = getRestartCause(RestartCause::powerButton);
664 }
665 else if (causeSet.contains(RestartCause::powerPolicyOn))
666 {
667 restartCause = getRestartCause(RestartCause::powerPolicyOn);
668 }
669 else if (causeSet.contains(RestartCause::powerPolicyRestore))
670 {
671 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
672 }
673 else if (causeSet.contains(RestartCause::softReset))
674 {
675 restartCause = getRestartCause(RestartCause::softReset);
676 }
677
678 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700679}
680
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700681static void systemPowerGoodFailedLog()
682{
683 sd_journal_send(
684 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
685 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
686 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700687 TimerMap["SioPowerGoodWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700688}
689
690static void psPowerOKFailedLog()
691{
692 sd_journal_send(
693 "MESSAGE=PowerControl: power supply power good failed to assert",
694 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
695 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700696 TimerMap["PsPowerOKWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700697}
698
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700699static void powerRestorePolicyLog()
700{
701 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
702 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
703 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
704}
705
706static void powerButtonPressLog()
707{
708 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
709 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
710 "OpenBMC.0.1.PowerButtonPressed", NULL);
711}
712
713static void resetButtonPressLog()
714{
715 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
716 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
717 "OpenBMC.0.1.ResetButtonPressed", NULL);
718}
719
720static void nmiButtonPressLog()
721{
722 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
723 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
724 "OpenBMC.0.1.NMIButtonPressed", NULL);
725}
726
727static void nmiDiagIntLog()
728{
729 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
730 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
731 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
732}
733
734static int initializePowerStateStorage()
735{
736 // create the power control directory if it doesn't exist
737 std::error_code ec;
738 if (!(std::filesystem::create_directories(powerControlDir, ec)))
739 {
740 if (ec.value() != 0)
741 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800742 lg2::error("failed to create {DIR_NAME}: {ERROR_MSG}", "DIR_NAME",
743 powerControlDir.string(), "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700744 return -1;
745 }
746 }
747 // Create the power state file if it doesn't exist
748 if (!std::filesystem::exists(powerControlDir / powerStateFile))
749 {
750 std::ofstream powerStateStream(powerControlDir / powerStateFile);
751 powerStateStream << getChassisState(powerState);
752 }
753 return 0;
754}
755
756static bool wasPowerDropped()
757{
758 std::ifstream powerStateStream(powerControlDir / powerStateFile);
759 if (!powerStateStream.is_open())
760 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800761 lg2::error("Failed to open power state file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700762 return false;
763 }
764
765 std::string state;
766 std::getline(powerStateStream, state);
767 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
768}
769
770static void invokePowerRestorePolicy(const std::string& policy)
771{
772 // Async events may call this twice, but we only want to run once
773 static bool policyInvoked = false;
774 if (policyInvoked)
775 {
776 return;
777 }
778 policyInvoked = true;
779
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800780 lg2::info("Power restore delay expired, invoking {POLICY}", "POLICY",
781 policy);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700782 if (policy ==
783 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
784 {
785 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700786 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700787 }
Jason M. Bills418ce112021-09-08 15:15:05 -0700788 else if (policy ==
789 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore")
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700790 {
791 if (wasPowerDropped())
792 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800793 lg2::info("Power was dropped, restoring Host On state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700794 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700795 setRestartCauseProperty(
796 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700797 }
798 else
799 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800800 lg2::info("No power drop, restoring Host Off state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700801 }
802 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -0700803 // We're done with the previous power state for the restore policy, so store
804 // the current state
805 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700806}
807
808static void powerRestorePolicyDelay(int delay)
809{
810 // Async events may call this twice, but we only want to run once
811 static bool delayStarted = false;
812 if (delayStarted)
813 {
814 return;
815 }
816 delayStarted = true;
817 // Calculate the delay from now to meet the requested delay
818 // Subtract the approximate uboot time
819 static constexpr const int ubootSeconds = 20;
820 delay -= ubootSeconds;
821 // Subtract the time since boot
822 struct sysinfo info = {};
823 if (sysinfo(&info) == 0)
824 {
825 delay -= info.uptime;
826 }
827 // 0 is the minimum delay
828 delay = std::max(delay, 0);
829
830 static boost::asio::steady_timer powerRestorePolicyTimer(io);
831 powerRestorePolicyTimer.expires_after(std::chrono::seconds(delay));
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800832 lg2::info("Power restore delay of {DELAY} seconds started", "DELAY", delay);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700833 powerRestorePolicyTimer.async_wait([](const boost::system::error_code ec) {
834 if (ec)
835 {
836 // operation_aborted is expected if timer is canceled before
837 // completion.
838 if (ec != boost::asio::error::operation_aborted)
839 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800840 lg2::error(
841 "power restore policy async_wait failed: {ERROR_MSG}",
842 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700843 }
844 return;
845 }
846 // Get Power Restore Policy
847 // In case PowerRestorePolicy is not available, set a match for it
848 static std::unique_ptr<sdbusplus::bus::match::match>
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800849 powerRestorePolicyMatch =
850 std::make_unique<sdbusplus::bus::match::match>(
851 *conn,
852 "type='signal',interface='org.freedesktop.DBus.Properties',"
853 "member='PropertiesChanged',arg0namespace='xyz.openbmc_"
854 "project.Control.Power.RestorePolicy'",
855 [](sdbusplus::message::message& msg) {
856 std::string interfaceName;
857 boost::container::flat_map<std::string,
858 std::variant<std::string>>
859 propertiesChanged;
860 std::string policy;
861 try
862 {
863 msg.read(interfaceName, propertiesChanged);
864 policy = std::get<std::string>(
865 propertiesChanged.begin()->second);
866 }
867 catch (const std::exception& e)
868 {
869 lg2::error(
870 "Unable to read restore policy value: {ERROR}",
871 "ERROR", e);
872 powerRestorePolicyMatch.reset();
873 return;
874 }
875 invokePowerRestorePolicy(policy);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700876 powerRestorePolicyMatch.reset();
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800877 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700878
879 // Check if it's already on DBus
880 conn->async_method_call(
881 [](boost::system::error_code ec,
882 const std::variant<std::string>& policyProperty) {
883 if (ec)
884 {
885 return;
886 }
887 powerRestorePolicyMatch.reset();
888 const std::string* policy =
889 std::get_if<std::string>(&policyProperty);
890 if (policy == nullptr)
891 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800892 lg2::error("Unable to read power restore policy value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700893 return;
894 }
895 invokePowerRestorePolicy(*policy);
896 },
897 "xyz.openbmc_project.Settings",
898 "/xyz/openbmc_project/control/host0/power_restore_policy",
899 "org.freedesktop.DBus.Properties", "Get",
900 "xyz.openbmc_project.Control.Power.RestorePolicy",
901 "PowerRestorePolicy");
902 });
903}
904
905static void powerRestorePolicyStart()
906{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800907 lg2::info("Power restore policy started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700908 powerRestorePolicyLog();
909
910 // Get the desired delay time
911 // In case PowerRestoreDelay is not available, set a match for it
912 static std::unique_ptr<sdbusplus::bus::match::match>
913 powerRestoreDelayMatch = std::make_unique<sdbusplus::bus::match::match>(
914 *conn,
915 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
916 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Control."
917 "Power.RestoreDelay'",
918 [](sdbusplus::message::message& msg) {
919 std::string interfaceName;
920 boost::container::flat_map<std::string, std::variant<uint16_t>>
921 propertiesChanged;
922 int delay = 0;
923 try
924 {
925 msg.read(interfaceName, propertiesChanged);
926 delay =
927 std::get<uint16_t>(propertiesChanged.begin()->second);
928 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -0500929 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700930 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800931 lg2::error(
932 "Unable to read power restore delay value: {ERROR}",
933 "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700934 powerRestoreDelayMatch.reset();
935 return;
936 }
937 powerRestorePolicyDelay(delay);
938 powerRestoreDelayMatch.reset();
939 });
940
941 // Check if it's already on DBus
942 conn->async_method_call(
943 [](boost::system::error_code ec,
944 const std::variant<uint16_t>& delayProperty) {
945 if (ec)
946 {
947 return;
948 }
949 powerRestoreDelayMatch.reset();
950 const uint16_t* delay = std::get_if<uint16_t>(&delayProperty);
951 if (delay == nullptr)
952 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800953 lg2::error("Unable to read power restore delay value");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700954 return;
955 }
956 powerRestorePolicyDelay(*delay);
957 },
958 "xyz.openbmc_project.Settings",
959 "/xyz/openbmc_project/control/power_restore_delay",
960 "org.freedesktop.DBus.Properties", "Get",
961 "xyz.openbmc_project.Control.Power.RestoreDelay", "PowerRestoreDelay");
962}
963
964static void powerRestorePolicyCheck()
965{
966 // In case ACBoot is not available, set a match for it
967 static std::unique_ptr<sdbusplus::bus::match::match> acBootMatch =
968 std::make_unique<sdbusplus::bus::match::match>(
969 *conn,
970 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
971 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Common."
972 "ACBoot'",
973 [](sdbusplus::message::message& msg) {
974 std::string interfaceName;
975 boost::container::flat_map<std::string,
976 std::variant<std::string>>
977 propertiesChanged;
978 std::string acBoot;
979 try
980 {
981 msg.read(interfaceName, propertiesChanged);
982 acBoot = std::get<std::string>(
983 propertiesChanged.begin()->second);
984 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -0500985 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700986 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800987 lg2::error("Unable to read AC Boot status: {ERROR}",
988 "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700989 acBootMatch.reset();
990 return;
991 }
992 if (acBoot == "Unknown")
993 {
994 return;
995 }
996 if (acBoot == "True")
997 {
998 // Start the Power Restore policy
999 powerRestorePolicyStart();
1000 }
1001 acBootMatch.reset();
1002 });
1003
1004 // Check if it's already on DBus
1005 conn->async_method_call(
1006 [](boost::system::error_code ec,
1007 const std::variant<std::string>& acBootProperty) {
1008 if (ec)
1009 {
1010 return;
1011 }
1012 const std::string* acBoot =
1013 std::get_if<std::string>(&acBootProperty);
1014 if (acBoot == nullptr)
1015 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001016 lg2::error("Unable to read AC Boot status");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001017 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 "xyz.openbmc_project.Settings",
1031 "/xyz/openbmc_project/control/host0/ac_boot",
1032 "org.freedesktop.DBus.Properties", "Get",
1033 "xyz.openbmc_project.Common.ACBoot", "ACBoot");
1034}
1035
Zev Weiss676ef2c2021-09-02 21:54:02 -05001036static void waitForGPIOEvent(const std::string& name,
1037 const std::function<void(bool)>& eventHandler,
1038 gpiod::line& line,
1039 boost::asio::posix::stream_descriptor& event)
1040{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001041 event.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1042 [&name, eventHandler, &line,
1043 &event](const boost::system::error_code ec) {
1044 if (ec)
1045 {
1046 lg2::error(
1047 "{GPIO_NAME} fd handler error: {ERROR_MSG}",
1048 "GPIO_NAME", name, "ERROR_MSG", ec.message());
1049 // TODO: throw here to force power-control to
1050 // restart?
1051 return;
1052 }
1053 gpiod::line_event line_event = line.event_read();
1054 eventHandler(line_event.event_type ==
1055 gpiod::line_event::RISING_EDGE);
1056 waitForGPIOEvent(name, eventHandler, line, event);
1057 });
Zev Weiss676ef2c2021-09-02 21:54:02 -05001058}
1059
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001060static bool requestGPIOEvents(
Zev Weiss676ef2c2021-09-02 21:54:02 -05001061 const std::string& name, const std::function<void(bool)>& handler,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001062 gpiod::line& gpioLine,
1063 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
1064{
1065 // Find the GPIO line
1066 gpioLine = gpiod::find_line(name);
1067 if (!gpioLine)
1068 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001069 lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001070 return false;
1071 }
1072
1073 try
1074 {
1075 gpioLine.request(
Jason M. Bills9fd8ac22021-10-21 15:14:17 -07001076 {"power-control", gpiod::line_request::EVENT_BOTH_EDGES, {}});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001077 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001078 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001079 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001080 lg2::error("Failed to request events for {GPIO_NAME}: {ERROR}",
1081 "GPIO_NAME", name, "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001082 return false;
1083 }
1084
1085 int gpioLineFd = gpioLine.event_get_fd();
1086 if (gpioLineFd < 0)
1087 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001088 lg2::error("Failed to get {GPIO_NAME} fd", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001089 return false;
1090 }
1091
1092 gpioEventDescriptor.assign(gpioLineFd);
1093
Zev Weiss676ef2c2021-09-02 21:54:02 -05001094 waitForGPIOEvent(name, handler, gpioLine, gpioEventDescriptor);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001095 return true;
1096}
1097
1098static bool setGPIOOutput(const std::string& name, const int value,
1099 gpiod::line& gpioLine)
1100{
1101 // Find the GPIO line
1102 gpioLine = gpiod::find_line(name);
1103 if (!gpioLine)
1104 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001105 lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001106 return false;
1107 }
1108
1109 // Request GPIO output to specified value
1110 try
1111 {
Jason M. Bills9fd8ac22021-10-21 15:14:17 -07001112 gpioLine.request(
1113 {__FUNCTION__, gpiod::line_request::DIRECTION_OUTPUT, {}}, value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001114 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001115 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001116 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001117 lg2::error("Failed to request {GPIO_NAME} output: {ERROR}", "GPIO_NAME",
1118 name, "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001119 return false;
1120 }
1121
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001122 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1123 "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001124 return true;
1125}
1126
1127static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1128 const std::string& name, const int value,
1129 const int durationMs)
1130{
1131 // Set the masked GPIO line to the specified value
1132 maskedGPIOLine.set_value(value);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001133 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1134 "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001135 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001136 gpioAssertTimer.async_wait(
1137 [maskedGPIOLine, value, name](const boost::system::error_code ec) {
1138 // Set the masked GPIO line back to the opposite value
1139 maskedGPIOLine.set_value(!value);
1140 lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
1141 if (ec)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001142 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001143 // operation_aborted is expected if timer is canceled before
1144 // completion.
1145 if (ec != boost::asio::error::operation_aborted)
1146 {
1147 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1148 "GPIO_NAME", name, "ERROR_MSG", ec.message());
1149 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001150 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001151 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001152 return 0;
1153}
1154
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001155static int setGPIOOutputForMs(const ConfigData& config, const int value,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001156 const int durationMs)
1157{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001158 // If the requested GPIO is masked, use the mask line to set the output
1159 if (powerButtonMask && config.lineName == powerOutConfig.lineName)
1160 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001161 return setMaskedGPIOOutputForMs(powerButtonMask, config.lineName, value,
1162 durationMs);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001163 }
1164 if (resetButtonMask && config.lineName == resetOutConfig.lineName)
1165 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001166 return setMaskedGPIOOutputForMs(resetButtonMask, config.lineName, value,
1167 durationMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001168 }
1169
1170 // No mask set, so request and set the GPIO normally
1171 gpiod::line gpioLine;
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001172 if (!setGPIOOutput(config.lineName, value, gpioLine))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001173 {
1174 return -1;
1175 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001176 const std::string name = config.lineName;
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001177
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001178 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001179 gpioAssertTimer.async_wait(
1180 [gpioLine, value, name](const boost::system::error_code ec) {
1181 // Set the GPIO line back to the opposite value
1182 gpioLine.set_value(!value);
1183 lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
1184 if (ec)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001185 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001186 // operation_aborted is expected if timer is canceled before
1187 // completion.
1188 if (ec != boost::asio::error::operation_aborted)
1189 {
1190 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1191 "GPIO_NAME", name, "ERROR_MSG", ec.message());
1192 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001193 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001194 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001195 return 0;
1196}
1197
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001198static int assertGPIOForMs(const ConfigData& config, const int durationMs)
1199{
1200 return setGPIOOutputForMs(config, config.polarity, durationMs);
1201}
1202
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001203static void powerOn()
1204{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001205 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001206}
Naveen Moses117c34e2021-05-26 20:10:51 +05301207#ifdef CHASSIS_SYSTEM_RESET
1208static int slotPowerOn()
1209{
1210 if (power_control::slotPowerState != power_control::SlotPowerState::on)
1211 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001212
Naveen Moses117c34e2021-05-26 20:10:51 +05301213 slotPowerLine.set_value(1);
1214
1215 if (slotPowerLine.get_value() > 0)
1216 {
1217 setSlotPowerState(SlotPowerState::on);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001218 lg2::info("Slot Power is switched On\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301219 }
1220 else
1221 {
1222 return -1;
1223 }
1224 }
1225 else
1226 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001227 lg2::info("Slot Power is already in 'On' state\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301228 return -1;
1229 }
1230 return 0;
1231}
1232static int slotPowerOff()
1233{
1234 if (power_control::slotPowerState != power_control::SlotPowerState::off)
1235 {
1236 slotPowerLine.set_value(0);
1237
1238 if (!(slotPowerLine.get_value() > 0))
1239 {
1240 setSlotPowerState(SlotPowerState::off);
1241 setPowerState(PowerState::off);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001242 lg2::info("Slot Power is switched Off\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301243 }
1244 else
1245 {
1246 return -1;
1247 }
1248 }
1249 else
1250 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001251 lg2::info("Slot Power is already in 'Off' state\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301252 return -1;
1253 }
1254 return 0;
1255}
1256static void slotPowerCycle()
1257{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001258 lg2::info("Slot Power Cycle started\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301259 slotPowerOff();
1260 slotPowerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001261 std::chrono::milliseconds(TimerMap["SlotPowerCycleMs"]));
Naveen Moses117c34e2021-05-26 20:10:51 +05301262 slotPowerCycleTimer.async_wait([](const boost::system::error_code ec) {
1263 if (ec)
1264 {
1265 if (ec != boost::asio::error::operation_aborted)
1266 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001267 lg2::error(
1268 "Slot Power cycle timer async_wait failed: {ERROR_MSG}",
1269 "ERROR_MSG", ec.message());
Naveen Moses117c34e2021-05-26 20:10:51 +05301270 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001271 lg2::info("Slot Power cycle timer canceled\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301272 return;
1273 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001274 lg2::info("Slot Power cycle timer completed\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301275 slotPowerOn();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001276 lg2::info("Slot Power Cycle Completed\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301277 });
1278}
1279#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001280static void gracefulPowerOff()
1281{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001282 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001283}
1284
1285static void forcePowerOff()
1286{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001287 if (assertGPIOForMs(powerOutConfig, TimerMap["ForceOffPulseMs"]) < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001288 {
1289 return;
1290 }
1291
Jason M. Billsc6961b62021-10-21 14:08:02 -07001292 // If the force off timer expires, then the power-button override failed
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001293 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1294 if (ec)
1295 {
1296 // operation_aborted is expected if timer is canceled before
1297 // completion.
1298 if (ec != boost::asio::error::operation_aborted)
1299 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001300 lg2::error("Force power off async_wait failed: {ERROR_MSG}",
1301 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001302 }
1303 return;
1304 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001305
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001306 lg2::error("Power-button override failed. Not sure what to do now.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001307 });
1308}
1309
1310static void reset()
1311{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001312 assertGPIOForMs(resetOutConfig, TimerMap["ResetPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001313}
1314
1315static void gracefulPowerOffTimerStart()
1316{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001317 lg2::info("Graceful power-off timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001318 gracefulPowerOffTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001319 std::chrono::seconds(TimerMap["GracefulPowerOffS"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001320 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1321 if (ec)
1322 {
1323 // operation_aborted is expected if timer is canceled before
1324 // completion.
1325 if (ec != boost::asio::error::operation_aborted)
1326 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001327 lg2::error("Graceful power-off async_wait failed: {ERROR_MSG}",
1328 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001329 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001330 lg2::info("Graceful power-off timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001331 return;
1332 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001333 lg2::info("Graceful power-off timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001334 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1335 });
1336}
1337
1338static void powerCycleTimerStart()
1339{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001340 lg2::info("Power-cycle timer started");
Priyatharshan P70120512020-09-16 18:47:20 +05301341 powerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001342 std::chrono::milliseconds(TimerMap["PowerCycleMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001343 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1344 if (ec)
1345 {
1346 // operation_aborted is expected if timer is canceled before
1347 // completion.
1348 if (ec != boost::asio::error::operation_aborted)
1349 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001350 lg2::error("Power-cycle async_wait failed: {ERROR_MSG}",
1351 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001352 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001353 lg2::info("Power-cycle timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001354 return;
1355 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001356 lg2::info("Power-cycle timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001357 sendPowerControlEvent(Event::powerCycleTimerExpired);
1358 });
1359}
1360
1361static void psPowerOKWatchdogTimerStart()
1362{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001363 lg2::info("power supply power OK watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001364 psPowerOKWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001365 std::chrono::milliseconds(TimerMap["PsPowerOKWatchdogMs"]));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001366 psPowerOKWatchdogTimer.async_wait([](const boost::system::error_code ec) {
1367 if (ec)
1368 {
1369 // operation_aborted is expected if timer is canceled before
1370 // completion.
1371 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001372 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001373 lg2::error(
1374 "power supply power OK watchdog async_wait failed: {ERROR_MSG}",
1375 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001376 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001377 lg2::info("power supply power OK watchdog timer canceled");
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001378 return;
1379 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001380 lg2::info("power supply power OK watchdog timer expired");
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001381 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1382 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001383}
1384
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001385static void warmResetCheckTimerStart()
1386{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001387 lg2::info("Warm reset check timer started");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001388 warmResetCheckTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001389 std::chrono::milliseconds(TimerMap["WarmResetCheckMs"]));
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001390 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1391 if (ec)
1392 {
1393 // operation_aborted is expected if timer is canceled before
1394 // completion.
1395 if (ec != boost::asio::error::operation_aborted)
1396 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001397 lg2::error("Warm reset check async_wait failed: {ERROR_MSG}",
1398 "ERROR_MSG", ec.message());
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001399 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001400 lg2::info("Warm reset check timer canceled");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001401 return;
1402 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001403 lg2::info("Warm reset check timer completed");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001404 sendPowerControlEvent(Event::warmResetDetected);
1405 });
1406}
1407
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001408static void pohCounterTimerStart()
1409{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001410 lg2::info("POH timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001411 // Set the time-out as 1 hour, to align with POH command in ipmid
1412 pohCounterTimer.expires_after(std::chrono::hours(1));
1413 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1414 if (ec)
1415 {
1416 // operation_aborted is expected if timer is canceled before
1417 // completion.
1418 if (ec != boost::asio::error::operation_aborted)
1419 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001420 lg2::error("POH timer async_wait failed: {ERROR_MSG}",
1421 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001422 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001423 lg2::info("POH timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001424 return;
1425 }
1426
1427 if (getHostState(powerState) !=
1428 "xyz.openbmc_project.State.Host.HostState.Running")
1429 {
1430 return;
1431 }
1432
1433 conn->async_method_call(
1434 [](boost::system::error_code ec,
1435 const std::variant<uint32_t>& pohCounterProperty) {
1436 if (ec)
1437 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001438 lg2::error("error getting poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001439 return;
1440 }
1441 const uint32_t* pohCounter =
1442 std::get_if<uint32_t>(&pohCounterProperty);
1443 if (pohCounter == nullptr)
1444 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001445 lg2::error("unable to read poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001446 return;
1447 }
1448
1449 conn->async_method_call(
1450 [](boost::system::error_code ec) {
1451 if (ec)
1452 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001453 lg2::error("failed to set poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001454 }
1455 },
1456 "xyz.openbmc_project.Settings",
1457 "/xyz/openbmc_project/state/chassis0",
1458 "org.freedesktop.DBus.Properties", "Set",
1459 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1460 std::variant<uint32_t>(*pohCounter + 1));
1461 },
1462 "xyz.openbmc_project.Settings",
1463 "/xyz/openbmc_project/state/chassis0",
1464 "org.freedesktop.DBus.Properties", "Get",
1465 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1466
1467 pohCounterTimerStart();
1468 });
1469}
1470
1471static void currentHostStateMonitor()
1472{
Yong Li8d660212019-12-27 10:18:10 +08001473 if (getHostState(powerState) ==
1474 "xyz.openbmc_project.State.Host.HostState.Running")
1475 {
1476 pohCounterTimerStart();
1477 // Clear the restart cause set for the next restart
1478 clearRestartCause();
1479 }
1480 else
1481 {
1482 pohCounterTimer.cancel();
1483 // Set the restart cause set for this restart
1484 setRestartCause();
1485 }
1486
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001487 static auto match = sdbusplus::bus::match::match(
1488 *conn,
1489 "type='signal',member='PropertiesChanged', "
1490 "interface='org.freedesktop.DBus.Properties', "
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001491 "arg0='xyz.openbmc_project.State.Host'",
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001492 [](sdbusplus::message::message& message) {
1493 std::string intfName;
1494 std::map<std::string, std::variant<std::string>> properties;
1495
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001496 try
1497 {
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001498 message.read(intfName, properties);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001499 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05001500 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001501 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001502 lg2::error("Unable to read host state: {ERROR}", "ERROR", e);
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001503 return;
1504 }
1505 if (properties.empty())
1506 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001507 lg2::error("ERROR: Empty PropertiesChanged signal received");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001508 return;
1509 }
1510
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001511 // We only want to check for CurrentHostState
1512 if (properties.begin()->first != "CurrentHostState")
1513 {
1514 return;
1515 }
1516 std::string* currentHostState =
1517 std::get_if<std::string>(&(properties.begin()->second));
1518 if (currentHostState == nullptr)
1519 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001520 lg2::error("{PROPERTY} property invalid", "PROPERTY",
1521 properties.begin()->first);
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001522 return;
1523 }
1524
1525 if (*currentHostState ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001526 "xyz.openbmc_project.State.Host.HostState.Running")
1527 {
1528 pohCounterTimerStart();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001529 // Clear the restart cause set for the next restart
1530 clearRestartCause();
Yong Li8d660212019-12-27 10:18:10 +08001531 sd_journal_send("MESSAGE=Host system DC power is on",
1532 "PRIORITY=%i", LOG_INFO,
1533 "REDFISH_MESSAGE_ID=%s",
1534 "OpenBMC.0.1.DCPowerOn", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001535 }
1536 else
1537 {
1538 pohCounterTimer.cancel();
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301539 // POST_COMPLETE GPIO event is not working in some platforms
1540 // when power state is changed to OFF. This resulted in
1541 // 'OperatingSystemState' to stay at 'Standby', even though
1542 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1543 // if HostState is trurned to OFF.
1544 osIface->set_property("OperatingSystemState",
1545 std::string("Inactive"));
1546
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001547 // Set the restart cause set for this restart
1548 setRestartCause();
Rashmi RV89f61312020-01-22 15:41:50 +05301549 resetACBootProperty();
Yong Li8d660212019-12-27 10:18:10 +08001550 sd_journal_send("MESSAGE=Host system DC power is off",
1551 "PRIORITY=%i", LOG_INFO,
1552 "REDFISH_MESSAGE_ID=%s",
1553 "OpenBMC.0.1.DCPowerOff", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001554 }
1555 });
1556}
1557
1558static void sioPowerGoodWatchdogTimerStart()
1559{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001560 lg2::info("SIO power good watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001561 sioPowerGoodWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001562 std::chrono::milliseconds(TimerMap["SioPowerGoodWatchdogMs"]));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001563 sioPowerGoodWatchdogTimer.async_wait([](const boost::system::error_code
1564 ec) {
1565 if (ec)
1566 {
1567 // operation_aborted is expected if timer is canceled before
1568 // completion.
1569 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001570 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001571 lg2::error(
1572 "SIO power good watchdog async_wait failed: {ERROR_MSG}",
1573 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001574 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001575 lg2::info("SIO power good watchdog timer canceled");
1576 return;
1577 }
1578 lg2::info("SIO power good watchdog timer completed");
1579 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1580 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001581}
1582
1583static void powerStateOn(const Event event)
1584{
1585 logEvent(__FUNCTION__, event);
1586 switch (event)
1587 {
1588 case Event::psPowerOKDeAssert:
1589 setPowerState(PowerState::off);
1590 // DC power is unexpectedly lost, beep
1591 beep(beepPowerFail);
1592 break;
1593 case Event::sioS5Assert:
1594 setPowerState(PowerState::transitionToOff);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001595 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001596 break;
Jason M. Billsfb957332021-01-28 13:18:46 -08001597#if USE_PLT_RST
1598 case Event::pltRstAssert:
1599#else
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001600 case Event::postCompleteDeAssert:
Jason M. Billsfb957332021-01-28 13:18:46 -08001601#endif
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001602 setPowerState(PowerState::checkForWarmReset);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001603 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001604 warmResetCheckTimerStart();
1605 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001606 case Event::powerButtonPressed:
1607 setPowerState(PowerState::gracefulTransitionToOff);
1608 gracefulPowerOffTimerStart();
1609 break;
1610 case Event::powerOffRequest:
1611 setPowerState(PowerState::transitionToOff);
1612 forcePowerOff();
1613 break;
1614 case Event::gracefulPowerOffRequest:
1615 setPowerState(PowerState::gracefulTransitionToOff);
1616 gracefulPowerOffTimerStart();
1617 gracefulPowerOff();
1618 break;
1619 case Event::powerCycleRequest:
1620 setPowerState(PowerState::transitionToCycleOff);
1621 forcePowerOff();
1622 break;
1623 case Event::gracefulPowerCycleRequest:
1624 setPowerState(PowerState::gracefulTransitionToCycleOff);
1625 gracefulPowerOffTimerStart();
1626 gracefulPowerOff();
1627 break;
1628 case Event::resetRequest:
1629 reset();
1630 break;
1631 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001632 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001633 break;
1634 }
1635}
1636
1637static void powerStateWaitForPSPowerOK(const Event event)
1638{
1639 logEvent(__FUNCTION__, event);
1640 switch (event)
1641 {
1642 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301643 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001644 // Cancel any GPIO assertions held during the transition
1645 gpioAssertTimer.cancel();
1646 psPowerOKWatchdogTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301647 if (sioEnabled == true)
1648 {
1649 sioPowerGoodWatchdogTimerStart();
1650 setPowerState(PowerState::waitForSIOPowerGood);
1651 }
1652 else
1653 {
1654 setPowerState(PowerState::on);
1655 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001656 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301657 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001658 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001659 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001660 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001661 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001662 case Event::sioPowerGoodAssert:
1663 psPowerOKWatchdogTimer.cancel();
1664 setPowerState(PowerState::on);
1665 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001666 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001667 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001668 break;
1669 }
1670}
1671
1672static void powerStateWaitForSIOPowerGood(const Event event)
1673{
1674 logEvent(__FUNCTION__, event);
1675 switch (event)
1676 {
1677 case Event::sioPowerGoodAssert:
1678 sioPowerGoodWatchdogTimer.cancel();
1679 setPowerState(PowerState::on);
1680 break;
1681 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001682 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001683 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001684 break;
1685 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001686 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001687 break;
1688 }
1689}
1690
1691static void powerStateOff(const Event event)
1692{
1693 logEvent(__FUNCTION__, event);
1694 switch (event)
1695 {
1696 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301697 {
1698 if (sioEnabled == true)
1699 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001700 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301701 setPowerState(PowerState::waitForSIOPowerGood);
1702 }
1703 else
1704 {
1705 setPowerState(PowerState::on);
1706 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001707 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301708 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001709 case Event::sioS5DeAssert:
1710 setPowerState(PowerState::waitForPSPowerOK);
1711 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001712 case Event::sioPowerGoodAssert:
1713 setPowerState(PowerState::on);
1714 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001715 case Event::powerButtonPressed:
1716 psPowerOKWatchdogTimerStart();
1717 setPowerState(PowerState::waitForPSPowerOK);
1718 break;
1719 case Event::powerOnRequest:
1720 psPowerOKWatchdogTimerStart();
1721 setPowerState(PowerState::waitForPSPowerOK);
1722 powerOn();
1723 break;
1724 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001725 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001726 break;
1727 }
1728}
1729
1730static void powerStateTransitionToOff(const Event event)
1731{
1732 logEvent(__FUNCTION__, event);
1733 switch (event)
1734 {
1735 case Event::psPowerOKDeAssert:
1736 // Cancel any GPIO assertions held during the transition
1737 gpioAssertTimer.cancel();
1738 setPowerState(PowerState::off);
1739 break;
1740 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001741 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001742 break;
1743 }
1744}
1745
1746static void powerStateGracefulTransitionToOff(const Event event)
1747{
1748 logEvent(__FUNCTION__, event);
1749 switch (event)
1750 {
1751 case Event::psPowerOKDeAssert:
1752 gracefulPowerOffTimer.cancel();
1753 setPowerState(PowerState::off);
1754 break;
1755 case Event::gracefulPowerOffTimerExpired:
1756 setPowerState(PowerState::on);
1757 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001758 case Event::powerOffRequest:
1759 gracefulPowerOffTimer.cancel();
1760 setPowerState(PowerState::transitionToOff);
1761 forcePowerOff();
1762 break;
1763 case Event::powerCycleRequest:
1764 gracefulPowerOffTimer.cancel();
1765 setPowerState(PowerState::transitionToCycleOff);
1766 forcePowerOff();
1767 break;
1768 case Event::resetRequest:
1769 gracefulPowerOffTimer.cancel();
1770 setPowerState(PowerState::on);
1771 reset();
1772 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001773 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001774 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001775 break;
1776 }
1777}
1778
1779static void powerStateCycleOff(const Event event)
1780{
1781 logEvent(__FUNCTION__, event);
1782 switch (event)
1783 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001784 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301785 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001786 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301787 if (sioEnabled == true)
1788 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001789 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301790 setPowerState(PowerState::waitForSIOPowerGood);
1791 }
1792 else
1793 {
1794 setPowerState(PowerState::on);
1795 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001796 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301797 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001798 case Event::sioS5DeAssert:
1799 powerCycleTimer.cancel();
1800 setPowerState(PowerState::waitForPSPowerOK);
1801 break;
1802 case Event::powerButtonPressed:
1803 powerCycleTimer.cancel();
1804 psPowerOKWatchdogTimerStart();
1805 setPowerState(PowerState::waitForPSPowerOK);
1806 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001807 case Event::powerCycleTimerExpired:
1808 psPowerOKWatchdogTimerStart();
1809 setPowerState(PowerState::waitForPSPowerOK);
1810 powerOn();
1811 break;
1812 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001813 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001814 break;
1815 }
1816}
1817
1818static void powerStateTransitionToCycleOff(const Event event)
1819{
1820 logEvent(__FUNCTION__, event);
1821 switch (event)
1822 {
1823 case Event::psPowerOKDeAssert:
1824 // Cancel any GPIO assertions held during the transition
1825 gpioAssertTimer.cancel();
1826 setPowerState(PowerState::cycleOff);
1827 powerCycleTimerStart();
1828 break;
1829 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001830 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001831 break;
1832 }
1833}
1834
1835static void powerStateGracefulTransitionToCycleOff(const Event event)
1836{
1837 logEvent(__FUNCTION__, event);
1838 switch (event)
1839 {
1840 case Event::psPowerOKDeAssert:
1841 gracefulPowerOffTimer.cancel();
1842 setPowerState(PowerState::cycleOff);
1843 powerCycleTimerStart();
1844 break;
1845 case Event::gracefulPowerOffTimerExpired:
1846 setPowerState(PowerState::on);
1847 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001848 case Event::powerOffRequest:
1849 gracefulPowerOffTimer.cancel();
1850 setPowerState(PowerState::transitionToOff);
1851 forcePowerOff();
1852 break;
1853 case Event::powerCycleRequest:
1854 gracefulPowerOffTimer.cancel();
1855 setPowerState(PowerState::transitionToCycleOff);
1856 forcePowerOff();
1857 break;
1858 case Event::resetRequest:
1859 gracefulPowerOffTimer.cancel();
1860 setPowerState(PowerState::on);
1861 reset();
1862 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001863 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001864 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001865 break;
1866 }
1867}
1868
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001869static void powerStateCheckForWarmReset(const Event event)
1870{
1871 logEvent(__FUNCTION__, event);
1872 switch (event)
1873 {
1874 case Event::sioS5Assert:
1875 warmResetCheckTimer.cancel();
1876 setPowerState(PowerState::transitionToOff);
1877 break;
1878 case Event::warmResetDetected:
1879 setPowerState(PowerState::on);
1880 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001881 case Event::psPowerOKDeAssert:
1882 warmResetCheckTimer.cancel();
1883 setPowerState(PowerState::off);
1884 // DC power is unexpectedly lost, beep
1885 beep(beepPowerFail);
1886 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001887 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001888 lg2::info("No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001889 break;
1890 }
1891}
1892
Zev Weiss584aa132021-09-02 19:21:52 -05001893static void psPowerOKHandler(bool state)
1894{
1895 Event powerControlEvent =
1896 state ? Event::psPowerOKAssert : Event::psPowerOKDeAssert;
1897 sendPowerControlEvent(powerControlEvent);
1898}
1899
Zev Weiss584aa132021-09-02 19:21:52 -05001900static void sioPowerGoodHandler(bool state)
1901{
1902 Event powerControlEvent =
1903 state ? Event::sioPowerGoodAssert : Event::sioPowerGoodDeAssert;
1904 sendPowerControlEvent(powerControlEvent);
1905}
1906
Zev Weiss584aa132021-09-02 19:21:52 -05001907static void sioOnControlHandler(bool state)
1908{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001909 lg2::info("SIO_ONCONTROL value changed: {VALUE}", "VALUE",
1910 static_cast<int>(state));
Zev Weiss584aa132021-09-02 19:21:52 -05001911}
1912
Zev Weiss584aa132021-09-02 19:21:52 -05001913static void sioS5Handler(bool state)
1914{
1915 Event powerControlEvent = state ? Event::sioS5DeAssert : Event::sioS5Assert;
1916 sendPowerControlEvent(powerControlEvent);
1917}
1918
Zev Weiss584aa132021-09-02 19:21:52 -05001919static void powerButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001920{
Zev Weiss584aa132021-09-02 19:21:52 -05001921 powerButtonIface->set_property("ButtonPressed", !state);
1922 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001923 {
1924 powerButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001925 if (!powerButtonMask)
1926 {
1927 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001928 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001929 }
1930 else
1931 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001932 lg2::info("power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001933 }
1934 }
Zev Weiss584aa132021-09-02 19:21:52 -05001935}
1936
Zev Weiss584aa132021-09-02 19:21:52 -05001937static void resetButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001938{
Zev Weiss584aa132021-09-02 19:21:52 -05001939 resetButtonIface->set_property("ButtonPressed", !state);
1940 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001941 {
1942 resetButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001943 if (!resetButtonMask)
1944 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001945 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001946 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001947 }
1948 else
1949 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001950 lg2::info("reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001951 }
1952 }
Zev Weiss584aa132021-09-02 19:21:52 -05001953}
1954
Vijay Khemka04175c22020-10-09 14:28:11 -07001955#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07001956static constexpr auto systemdBusname = "org.freedesktop.systemd1";
1957static constexpr auto systemdPath = "/org/freedesktop/systemd1";
1958static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
1959static constexpr auto systemTargetName = "chassis-system-reset.target";
1960
1961void systemReset()
1962{
1963 conn->async_method_call(
1964 [](boost::system::error_code ec) {
1965 if (ec)
1966 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001967 lg2::error("Failed to call chassis system reset: {ERR}", "ERR",
1968 ec.message());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07001969 }
1970 },
1971 systemdBusname, systemdPath, systemdInterface, "StartUnit",
1972 systemTargetName, "replace");
1973}
Vijay Khemka04175c22020-10-09 14:28:11 -07001974#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07001975
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001976static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001977{
1978 conn->async_method_call(
1979 [](boost::system::error_code ec) {
1980 if (ec)
1981 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001982 lg2::error("failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001983 }
1984 },
Chen Yugang303bd582019-11-01 08:45:06 +08001985 "xyz.openbmc_project.Settings",
1986 "/xyz/openbmc_project/Chassis/Control/NMISource",
1987 "org.freedesktop.DBus.Properties", "Set",
1988 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
1989 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001990}
1991
1992static void nmiReset(void)
1993{
1994 static constexpr const uint8_t value = 1;
1995 const static constexpr int nmiOutPulseTimeMs = 200;
1996
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001997 lg2::info("NMI out action");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001998 nmiOutLine.set_value(value);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001999 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME",
2000 nmiOutConfig.lineName, "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002001 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2002 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2003 // restore the NMI_OUT GPIO line back to the opposite value
2004 nmiOutLine.set_value(!value);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002005 lg2::info("{GPIO_NAME} released", "GPIO_NAME", nmiOutConfig.lineName);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002006 if (ec)
2007 {
2008 // operation_aborted is expected if timer is canceled before
2009 // completion.
2010 if (ec != boost::asio::error::operation_aborted)
2011 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002012 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
2013 "GPIO_NAME", nmiOutConfig.lineName, "ERROR_MSG",
2014 ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002015 }
2016 }
2017 });
2018 // log to redfish
2019 nmiDiagIntLog();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002020 lg2::info("NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002021 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002022 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002023}
2024
2025static void nmiSourcePropertyMonitor(void)
2026{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002027 lg2::info("NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002028
2029 static std::unique_ptr<sdbusplus::bus::match::match> nmiSourceMatch =
2030 std::make_unique<sdbusplus::bus::match::match>(
2031 *conn,
2032 "type='signal',interface='org.freedesktop.DBus.Properties',"
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002033 "member='PropertiesChanged',"
2034 "arg0namespace='xyz.openbmc_project.Chassis.Control.NMISource'",
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002035 [](sdbusplus::message::message& msg) {
2036 std::string interfaceName;
2037 boost::container::flat_map<std::string,
2038 std::variant<bool, std::string>>
2039 propertiesChanged;
2040 std::string state;
2041 bool value = true;
2042 try
2043 {
2044 msg.read(interfaceName, propertiesChanged);
2045 if (propertiesChanged.begin()->first == "Enabled")
2046 {
2047 value =
2048 std::get<bool>(propertiesChanged.begin()->second);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002049 lg2::info(
2050 "NMI Enabled propertiesChanged value: {VALUE}",
2051 "VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002052 nmiEnabled = value;
2053 if (nmiEnabled)
2054 {
2055 nmiReset();
2056 }
2057 }
2058 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002059 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002060 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002061 lg2::error("Unable to read NMI source: {ERROR}", "ERROR",
2062 e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002063 return;
2064 }
2065 });
2066}
2067
2068static void setNmiSource()
2069{
2070 conn->async_method_call(
2071 [](boost::system::error_code ec) {
2072 if (ec)
2073 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002074 lg2::error("failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002075 }
2076 },
Chen Yugang303bd582019-11-01 08:45:06 +08002077 "xyz.openbmc_project.Settings",
2078 "/xyz/openbmc_project/Chassis/Control/NMISource",
2079 "org.freedesktop.DBus.Properties", "Set",
2080 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
Jason M. Bills418ce112021-09-08 15:15:05 -07002081 std::variant<std::string>{
2082 "xyz.openbmc_project.Chassis.Control.NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002083 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002084 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002085}
2086
Zev Weiss584aa132021-09-02 19:21:52 -05002087static void nmiButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002088{
Zev Weiss584aa132021-09-02 19:21:52 -05002089 nmiButtonIface->set_property("ButtonPressed", !state);
2090 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002091 {
2092 nmiButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002093 if (nmiButtonMasked)
2094 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002095 lg2::info("NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002096 }
2097 else
2098 {
2099 setNmiSource();
2100 }
2101 }
Zev Weiss584aa132021-09-02 19:21:52 -05002102}
2103
Zev Weiss584aa132021-09-02 19:21:52 -05002104static void idButtonHandler(bool state)
2105{
2106 idButtonIface->set_property("ButtonPressed", !state);
2107}
2108
Jason M. Billsfb957332021-01-28 13:18:46 -08002109static void pltRstHandler(bool pltRst)
2110{
2111 if (pltRst)
2112 {
2113 sendPowerControlEvent(Event::pltRstDeAssert);
2114 }
2115 else
2116 {
2117 sendPowerControlEvent(Event::pltRstAssert);
2118 }
2119}
2120
Jason M. Bills9fd8ac22021-10-21 15:14:17 -07002121[[maybe_unused]] static void hostMiscHandler(sdbusplus::message::message& msg)
Jason M. Billsfb957332021-01-28 13:18:46 -08002122{
2123 std::string interfaceName;
2124 boost::container::flat_map<std::string, std::variant<bool>>
2125 propertiesChanged;
Jason M. Billsfb957332021-01-28 13:18:46 -08002126 try
2127 {
2128 msg.read(interfaceName, propertiesChanged);
2129 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002130 catch (const std::exception& e)
Jason M. Billsfb957332021-01-28 13:18:46 -08002131 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002132 lg2::error("Unable to read Host Misc status: {ERROR}", "ERROR", e);
Jason M. Billsfb957332021-01-28 13:18:46 -08002133 return;
2134 }
2135 if (propertiesChanged.empty())
2136 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002137 lg2::error("ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002138 return;
2139 }
2140
2141 for (auto& [property, value] : propertiesChanged)
2142 {
2143 if (property == "ESpiPlatformReset")
2144 {
2145 bool* pltRst = std::get_if<bool>(&value);
2146 if (pltRst == nullptr)
2147 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002148 lg2::error("{PROPERTY} property invalid", "PROPERTY", property);
Jason M. Billsfb957332021-01-28 13:18:46 -08002149 return;
2150 }
2151 pltRstHandler(*pltRst);
2152 }
2153 }
2154}
2155
Zev Weiss584aa132021-09-02 19:21:52 -05002156static void postCompleteHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002157{
Zev Weiss584aa132021-09-02 19:21:52 -05002158 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002159 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002160 sendPowerControlEvent(Event::postCompleteAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002161 osIface->set_property("OperatingSystemState", std::string("Standby"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002162 }
2163 else
2164 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002165 sendPowerControlEvent(Event::postCompleteDeAssert);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002166 osIface->set_property("OperatingSystemState", std::string("Inactive"));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002167 }
Zev Weiss584aa132021-09-02 19:21:52 -05002168}
2169
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302170static int loadConfigValues()
2171{
2172 const std::string configFilePath =
2173 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2174 ".json";
2175 std::ifstream configFile(configFilePath.c_str());
2176 if (!configFile.is_open())
2177 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002178 lg2::error("loadConfigValues: Cannot open config path \'{PATH}\'",
2179 "PATH", configFilePath);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302180 return -1;
2181 }
Zev Weiss1aa08b22021-09-15 17:06:20 -05002182 auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302183
Priyatharshan P70120512020-09-16 18:47:20 +05302184 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302185 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002186 lg2::error("Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302187 return -1;
2188 }
Priyatharshan P70120512020-09-16 18:47:20 +05302189 auto gpios = jsonData["gpio_configs"];
2190 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302191
Priyatharshan P70120512020-09-16 18:47:20 +05302192 ConfigData* tempGpioData;
2193
2194 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302195 {
Priyatharshan P70120512020-09-16 18:47:20 +05302196 if (!gpioConfig.contains("Name"))
2197 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002198 lg2::error("The 'Name' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302199 return -1;
2200 }
2201
2202 // Iterate through the powersignal map to check if the gpio json config
2203 // entry is valid
2204 std::string gpioName = gpioConfig["Name"];
2205 auto signalMapIter = powerSignalMap.find(gpioName);
2206 if (signalMapIter == powerSignalMap.end())
2207 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002208 lg2::error(
2209 "{GPIO_NAME} is not a recognized power-control signal name",
2210 "GPIO_NAME", gpioName);
Priyatharshan P70120512020-09-16 18:47:20 +05302211 return -1;
2212 }
2213
2214 // assign the power signal name to the corresponding structure reference
2215 // from map then fillup the structure with coressponding json config
2216 // value
2217 tempGpioData = signalMapIter->second;
2218 tempGpioData->name = gpioName;
2219
2220 if (!gpioConfig.contains("Type"))
2221 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002222 lg2::error("The \'Type\' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302223 return -1;
2224 }
2225
2226 std::string signalType = gpioConfig["Type"];
2227 if (signalType == "GPIO")
2228 {
2229 tempGpioData->type = ConfigType::GPIO;
2230 }
2231 else if (signalType == "DBUS")
2232 {
2233 tempGpioData->type = ConfigType::DBUS;
2234 }
2235 else
2236 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002237 lg2::error("{TYPE} is not a recognized power-control signal type",
2238 "TYPE", signalType);
Priyatharshan P70120512020-09-16 18:47:20 +05302239 return -1;
2240 }
2241
2242 if (tempGpioData->type == ConfigType::GPIO)
2243 {
2244 if (gpioConfig.contains("LineName"))
2245 {
2246 tempGpioData->lineName = gpioConfig["LineName"];
2247 }
2248 else
2249 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002250 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002251 "The \'LineName\' field must be defined for GPIO configuration");
Priyatharshan P70120512020-09-16 18:47:20 +05302252 return -1;
2253 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002254 if (gpioConfig.contains("Polarity"))
2255 {
2256 std::string polarity = gpioConfig["Polarity"];
2257 if (polarity == "ActiveLow")
2258 {
2259 tempGpioData->polarity = false;
2260 }
2261 else if (polarity == "ActiveHigh")
2262 {
2263 tempGpioData->polarity = true;
2264 }
2265 else
2266 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002267 lg2::error(
2268 "Polarity defined but not properly setup. Please only ActiveHigh or ActiveLow. Currently set to {POLARITY}",
2269 "POLARITY", polarity);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002270 return -1;
2271 }
2272 }
2273 else
2274 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002275 lg2::error("Polarity field not found for {GPIO_NAME}",
2276 "GPIO_NAME", tempGpioData->lineName);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002277 return -1;
2278 }
Priyatharshan P70120512020-09-16 18:47:20 +05302279 }
2280 else
2281 {
2282 // if dbus based gpio config is defined read and update the dbus
2283 // params corresponding to the gpio config instance
2284 for (auto& [key, dbusParamName] : dbusParams)
2285 {
Logananth Sundararaja4308042021-10-20 11:52:05 +05302286 if (!gpioConfig.contains(dbusParamName))
Priyatharshan P70120512020-09-16 18:47:20 +05302287 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002288 lg2::error(
2289 "The {DBUS_NAME} field must be defined for Dbus configuration ",
2290 "DBUS_NAME", dbusParamName);
Priyatharshan P70120512020-09-16 18:47:20 +05302291 return -1;
2292 }
2293 }
Logananth Sundararaja4308042021-10-20 11:52:05 +05302294 tempGpioData->dbusName =
2295 gpioConfig[dbusParams[DbusConfigType::name]];
2296 tempGpioData->path = gpioConfig[dbusParams[DbusConfigType::path]];
Priyatharshan P70120512020-09-16 18:47:20 +05302297 tempGpioData->interface =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302298 gpioConfig[dbusParams[DbusConfigType::interface]];
Priyatharshan P70120512020-09-16 18:47:20 +05302299 tempGpioData->lineName =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302300 gpioConfig[dbusParams[DbusConfigType::property]];
Priyatharshan P70120512020-09-16 18:47:20 +05302301 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302302 }
2303
Priyatharshan P70120512020-09-16 18:47:20 +05302304 // read and store the timer values from json config to Timer Map
2305 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302306 {
Priyatharshan P70120512020-09-16 18:47:20 +05302307 if (timers.contains(key.c_str()))
2308 {
2309 timerValue = timers[key.c_str()];
2310 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302311 }
2312
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302313 return 0;
2314}
Zev Weissa8f116a2021-09-01 21:08:30 -05002315
2316static bool getDbusMsgGPIOState(sdbusplus::message::message& msg,
2317 const std::string& lineName, bool& value)
2318{
2319 std::string thresholdInterface;
2320 std::string event;
2321 boost::container::flat_map<std::string, std::variant<bool>>
2322 propertiesChanged;
2323 try
2324 {
2325 msg.read(thresholdInterface, propertiesChanged);
2326 if (propertiesChanged.empty())
2327 {
2328 return false;
2329 }
2330
2331 event = propertiesChanged.begin()->first;
2332 if (event.empty() || event != lineName)
2333 {
2334 return false;
2335 }
2336
2337 value = std::get<bool>(propertiesChanged.begin()->second);
2338 return true;
2339 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002340 catch (const std::exception& e)
Zev Weissa8f116a2021-09-01 21:08:30 -05002341 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002342 lg2::error(
2343 "exception while reading dbus property \'{DBUS_NAME}\': {ERROR}",
2344 "DBUS_NAME", lineName, "ERROR", e);
Zev Weissa8f116a2021-09-01 21:08:30 -05002345 return false;
2346 }
2347}
2348
2349static sdbusplus::bus::match::match
2350 dbusGPIOMatcher(const ConfigData& cfg, std::function<void(bool)> onMatch)
2351{
2352 auto pulseEventMatcherCallback =
2353 [&cfg, onMatch](sdbusplus::message::message& msg) {
2354 bool value = false;
2355 if (!getDbusMsgGPIOState(msg, cfg.lineName, value))
2356 {
2357 return;
2358 }
2359 onMatch(value);
2360 };
2361
2362 return sdbusplus::bus::match::match(
2363 static_cast<sdbusplus::bus::bus&>(*conn),
2364 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2365 "PropertiesChanged',arg0='" +
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302366 cfg.interface + "'",
Zev Weissa8f116a2021-09-01 21:08:30 -05002367 std::move(pulseEventMatcherCallback));
2368}
2369
Priyatharshan P70120512020-09-16 18:47:20 +05302370int getProperty(ConfigData& configData)
2371{
2372 auto method = conn->new_method_call(
2373 configData.dbusName.c_str(), configData.path.c_str(),
2374 "org.freedesktop.DBus.Properties", "Get");
2375 method.append(configData.interface.c_str(), configData.lineName.c_str());
2376
2377 auto reply = conn->call(method);
2378 if (reply.is_method_error())
2379 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002380 lg2::error(
2381 "Error reading {PROPERTY} D-Bus property on interface {INTERFACE} and path {PATH}",
2382 "PROPERTY", configData.lineName, "INTERFACE", configData.interface,
2383 "PATH", configData.path);
Priyatharshan P70120512020-09-16 18:47:20 +05302384 return -1;
2385 }
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302386 std::variant<bool> resp;
Priyatharshan P70120512020-09-16 18:47:20 +05302387 reply.read(resp);
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302388 auto respValue = std::get_if<bool>(&resp);
Priyatharshan P70120512020-09-16 18:47:20 +05302389 if (!respValue)
2390 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002391 lg2::error("Error: {PROPERTY} D-Bus property is not the expected type",
2392 "PROPERTY", configData.lineName);
Priyatharshan P70120512020-09-16 18:47:20 +05302393 return -1;
2394 }
2395 return (*respValue);
2396}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002397} // namespace power_control
2398
2399int main(int argc, char* argv[])
2400{
Lei YU92caa4c2021-02-23 16:59:25 +08002401 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05302402
2403 if (argc > 1)
2404 {
2405 node = argv[1];
2406 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002407 lg2::info("Start Chassis power control service for host : {NODE}", "NODE",
2408 node);
Priyatharshan P70120512020-09-16 18:47:20 +05302409
Lei YU92caa4c2021-02-23 16:59:25 +08002410 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002411
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302412 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08002413 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302414 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002415 lg2::error("Host{NODE}: Error in Parsing...", "NODE", node);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302416 }
Naveen Mosesec972d82021-07-16 21:19:23 +05302417 /* Currently for single host based systems additional busname is added
2418 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
2419 Going forward for single hosts the old bus name without zero numbering
2420 will be removed when all other applications adapted to the
2421 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
2422
2423 if (node == "0")
2424 {
2425 // Request all the dbus names
2426 conn->request_name(hostDbusName.c_str());
2427 conn->request_name(chassisDbusName.c_str());
2428 conn->request_name(osDbusName.c_str());
2429 conn->request_name(buttonDbusName.c_str());
2430 conn->request_name(nmiDbusName.c_str());
2431 conn->request_name(rstCauseDbusName.c_str());
2432 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302433
Zev Weissc4005bd2021-09-01 22:30:23 -05002434 hostDbusName += node;
2435 chassisDbusName += node;
2436 osDbusName += node;
2437 buttonDbusName += node;
2438 nmiDbusName += node;
2439 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002440
Priyatharshan P70120512020-09-16 18:47:20 +05302441 // Request all the dbus names
2442 conn->request_name(hostDbusName.c_str());
2443 conn->request_name(chassisDbusName.c_str());
2444 conn->request_name(osDbusName.c_str());
2445 conn->request_name(buttonDbusName.c_str());
2446 conn->request_name(nmiDbusName.c_str());
2447 conn->request_name(rstCauseDbusName.c_str());
2448
2449 if (sioPwrGoodConfig.lineName.empty() ||
2450 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05302451 {
Lei YU92caa4c2021-02-23 16:59:25 +08002452 sioEnabled = false;
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002453 lg2::info("SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05302454 }
2455
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002456 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302457 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002458 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002459 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302460 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302461 {
2462 return -1;
2463 }
2464 }
Priyatharshan P70120512020-09-16 18:47:20 +05302465 else if (powerOkConfig.type == ConfigType::DBUS)
2466 {
2467
2468 static sdbusplus::bus::match::match powerOkEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002469 power_control::dbusGPIOMatcher(powerOkConfig, psPowerOKHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302470 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302471 else
2472 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002473 lg2::error("PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002474 return -1;
2475 }
2476
Lei YU92caa4c2021-02-23 16:59:25 +08002477 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002478 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05302479 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302480 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302481 {
Priyatharshan P70120512020-09-16 18:47:20 +05302482 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002483 sioPowerGoodHandler, sioPowerGoodLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302484 sioPowerGoodEvent))
2485 {
2486 return -1;
2487 }
2488 }
2489 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
2490 {
2491 static sdbusplus::bus::match::match sioPwrGoodEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002492 power_control::dbusGPIOMatcher(sioPwrGoodConfig,
2493 sioPowerGoodHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302494 }
2495 else
2496 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002497 lg2::error(
Priyatharshan P70120512020-09-16 18:47:20 +05302498 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302499 return -1;
2500 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002501
Priyatharshan P19c47a32020-08-12 18:16:43 +05302502 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302503 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302504 {
Priyatharshan P70120512020-09-16 18:47:20 +05302505 if (!requestGPIOEvents(sioOnControlConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002506 sioOnControlHandler, sioOnControlLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302507 sioOnControlEvent))
2508 {
2509 return -1;
2510 }
2511 }
2512 else if (sioOnControlConfig.type == ConfigType::DBUS)
2513 {
2514 static sdbusplus::bus::match::match sioOnControlEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002515 power_control::dbusGPIOMatcher(sioOnControlConfig,
2516 sioOnControlHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302517 }
2518 else
2519 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002520 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002521 "sioOnControl name should be configured from jsonconfig file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302522 return -1;
2523 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002524
Priyatharshan P19c47a32020-08-12 18:16:43 +05302525 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302526 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302527 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002528 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
Priyatharshan P70120512020-09-16 18:47:20 +05302529 sioS5Line, sioS5Event))
2530 {
2531 return -1;
2532 }
2533 }
2534 else if (sioS5Config.type == ConfigType::DBUS)
2535 {
2536 static sdbusplus::bus::match::match sioS5EventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002537 power_control::dbusGPIOMatcher(sioS5Config, sioS5Handler);
Priyatharshan P70120512020-09-16 18:47:20 +05302538 }
2539 else
2540 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002541 lg2::error("sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302542 return -1;
2543 }
2544 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002545
2546 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302547 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002548 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002549 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
2550 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302551 {
2552 return -1;
2553 }
2554 }
Priyatharshan P70120512020-09-16 18:47:20 +05302555 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302556 {
Priyatharshan P70120512020-09-16 18:47:20 +05302557 static sdbusplus::bus::match::match powerButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002558 power_control::dbusGPIOMatcher(powerButtonConfig,
2559 powerButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002560 }
2561
2562 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302563 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002564 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002565 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
2566 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302567 {
2568 return -1;
2569 }
2570 }
Priyatharshan P70120512020-09-16 18:47:20 +05302571 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302572 {
Priyatharshan P70120512020-09-16 18:47:20 +05302573 static sdbusplus::bus::match::match resetButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002574 power_control::dbusGPIOMatcher(resetButtonConfig,
2575 resetButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002576 }
2577
2578 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302579 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302580 {
Priyatharshan P70120512020-09-16 18:47:20 +05302581 if (!nmiButtonConfig.lineName.empty())
2582 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002583 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302584 nmiButtonLine, nmiButtonEvent);
2585 }
2586 }
2587 else if (nmiButtonConfig.type == ConfigType::DBUS)
2588 {
2589 static sdbusplus::bus::match::match nmiButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002590 power_control::dbusGPIOMatcher(nmiButtonConfig, nmiButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302591 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002592
2593 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302594 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302595 {
Priyatharshan P70120512020-09-16 18:47:20 +05302596 if (!idButtonConfig.lineName.empty())
2597 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002598 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302599 idButtonLine, idButtonEvent);
2600 }
2601 }
2602 else if (idButtonConfig.type == ConfigType::DBUS)
2603 {
2604 static sdbusplus::bus::match::match idButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002605 power_control::dbusGPIOMatcher(idButtonConfig, idButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302606 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002607
Jason M. Billsfb957332021-01-28 13:18:46 -08002608#ifdef USE_PLT_RST
2609 sdbusplus::bus::match::match pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08002610 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08002611 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2612 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08002613 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08002614#endif
2615
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002616 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302617 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002618 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002619 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
2620 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302621 {
2622 return -1;
2623 }
2624 }
Priyatharshan P70120512020-09-16 18:47:20 +05302625 else if (postCompleteConfig.type == ConfigType::DBUS)
2626 {
2627 static sdbusplus::bus::match::match postCompleteEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002628 power_control::dbusGPIOMatcher(postCompleteConfig,
2629 postCompleteHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302630 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302631 else
2632 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002633 lg2::error(
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002634 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002635 return -1;
2636 }
2637
2638 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05302639 if (!nmiOutConfig.lineName.empty())
2640 {
2641 setGPIOOutput(nmiOutConfig.lineName, 0, nmiOutLine);
2642 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002643
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002644 // Initialize POWER_OUT and RESET_OUT GPIO.
2645 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05302646 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002647 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002648 if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
2649 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302650 {
2651 return -1;
2652 }
2653 }
2654 else
2655 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002656 lg2::error("powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002657 return -1;
2658 }
2659
Priyatharshan P70120512020-09-16 18:47:20 +05302660 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002661 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002662 if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
2663 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302664 {
2665 return -1;
2666 }
2667 }
2668 else
2669 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002670 lg2::error("ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002671 return -1;
2672 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002673 // Release line
2674 line.reset();
2675
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002676 // Initialize the power state
Lei YU92caa4c2021-02-23 16:59:25 +08002677 powerState = PowerState::off;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002678 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05302679
2680 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002681 {
Jean-Marie Verdun61b4a5b2021-09-19 08:53:28 -04002682 if (psPowerOKLine.get_value() > 0 ||
Lei YUa37c2472021-09-26 15:57:12 +08002683 (sioEnabled &&
2684 (sioPowerGoodLine.get_value() == sioPwrGoodConfig.polarity)))
Priyatharshan P70120512020-09-16 18:47:20 +05302685 {
2686 powerState = PowerState::on;
2687 }
2688 }
2689 else
2690 {
2691 if (getProperty(powerOkConfig))
2692 {
2693 powerState = PowerState::on;
2694 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002695 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002696 // Initialize the power state storage
Lei YU92caa4c2021-02-23 16:59:25 +08002697 if (initializePowerStateStorage() < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002698 {
2699 return -1;
2700 }
2701
2702 // Check if we need to start the Power Restore policy
Lei YU92caa4c2021-02-23 16:59:25 +08002703 powerRestorePolicyCheck();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002704
Lei YU92caa4c2021-02-23 16:59:25 +08002705 if (nmiOutLine)
2706 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002707
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002708 lg2::info("Initializing power state.");
Lei YU92caa4c2021-02-23 16:59:25 +08002709 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002710
2711 // Power Control Service
2712 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002713 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002714
2715 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05302716 hostIface =
2717 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
2718 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002719 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08002720 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002721 "RequestedHostTransition",
2722 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2723 [](const std::string& requested, std::string& resp) {
2724 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2725 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002726 // if power button is masked, ignore this
2727 if (!powerButtonMask)
2728 {
2729 sendPowerControlEvent(Event::gracefulPowerOffRequest);
2730 addRestartCause(RestartCause::command);
2731 }
2732 else
2733 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002734 lg2::info("Power Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002735 throw std::invalid_argument("Transition Request Masked");
2736 return 0;
2737 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002738 }
2739 else if (requested ==
2740 "xyz.openbmc_project.State.Host.Transition.On")
2741 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002742 // if power button is masked, ignore this
2743 if (!powerButtonMask)
2744 {
2745 sendPowerControlEvent(Event::powerOnRequest);
2746 addRestartCause(RestartCause::command);
2747 }
2748 else
2749 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002750 lg2::info("Power Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002751 throw std::invalid_argument("Transition Request Masked");
2752 return 0;
2753 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002754 }
2755 else if (requested ==
2756 "xyz.openbmc_project.State.Host.Transition.Reboot")
2757 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002758 // if power button is masked, ignore this
2759 if (!powerButtonMask)
2760 {
2761 sendPowerControlEvent(Event::powerCycleRequest);
2762 addRestartCause(RestartCause::command);
2763 }
2764 else
2765 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002766 lg2::info("Power Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002767 throw std::invalid_argument("Transition Request Masked");
2768 return 0;
2769 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002770 }
Jason M. Bills418ce112021-09-08 15:15:05 -07002771 else if (
2772 requested ==
2773 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot")
Jason M. Billse7520ba2020-01-31 11:19:03 -08002774 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002775 // if reset button is masked, ignore this
2776 if (!resetButtonMask)
2777 {
2778 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
2779 addRestartCause(RestartCause::command);
2780 }
2781 else
2782 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002783 lg2::info("Reset Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002784 throw std::invalid_argument("Transition Request Masked");
2785 return 0;
2786 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002787 }
Jason M. Bills418ce112021-09-08 15:15:05 -07002788 else if (
2789 requested ==
2790 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot")
Jason M. Billse7520ba2020-01-31 11:19:03 -08002791 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002792 // if reset button is masked, ignore this
2793 if (!resetButtonMask)
2794 {
2795 sendPowerControlEvent(Event::resetRequest);
2796 addRestartCause(RestartCause::command);
2797 }
2798 else
2799 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002800 lg2::info("Reset Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002801 throw std::invalid_argument("Transition Request Masked");
2802 return 0;
2803 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002804 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002805 else
2806 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002807 lg2::error("Unrecognized host state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002808 throw std::invalid_argument("Unrecognized Transition Request");
2809 return 0;
2810 }
2811 resp = requested;
2812 return 1;
2813 });
Lei YU92caa4c2021-02-23 16:59:25 +08002814 hostIface->register_property("CurrentHostState",
2815 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002816
Lei YU92caa4c2021-02-23 16:59:25 +08002817 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002818
2819 // Chassis Control Service
2820 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002821 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002822
2823 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002824 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05302825 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002826 "xyz.openbmc_project.State.Chassis");
2827
Lei YU92caa4c2021-02-23 16:59:25 +08002828 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002829 "RequestedPowerTransition",
2830 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
2831 [](const std::string& requested, std::string& resp) {
2832 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
2833 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002834 // if power button is masked, ignore this
2835 if (!powerButtonMask)
2836 {
2837 sendPowerControlEvent(Event::powerOffRequest);
2838 addRestartCause(RestartCause::command);
2839 }
2840 else
2841 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002842 lg2::info("Power Button Masked.");
Vernon Mauery2a269432021-07-14 10:00:21 -07002843 throw std::invalid_argument("Transition Request Masked");
2844 return 0;
2845 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002846 }
2847 else if (requested ==
2848 "xyz.openbmc_project.State.Chassis.Transition.On")
2849 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002850 // if power button is masked, ignore this
2851 if (!powerButtonMask)
2852 {
2853 sendPowerControlEvent(Event::powerOnRequest);
2854 addRestartCause(RestartCause::command);
2855 }
2856 else
2857 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002858 lg2::info("Power Button Masked.");
Vernon Mauery2a269432021-07-14 10:00:21 -07002859 throw std::invalid_argument("Transition Request Masked");
2860 return 0;
2861 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002862 }
2863 else if (requested ==
2864 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2865 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002866 // if power button is masked, ignore this
2867 if (!powerButtonMask)
2868 {
2869 sendPowerControlEvent(Event::powerCycleRequest);
2870 addRestartCause(RestartCause::command);
2871 }
2872 else
2873 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002874 lg2::info("Power Button Masked.");
Vernon Mauery2a269432021-07-14 10:00:21 -07002875 throw std::invalid_argument("Transition Request Masked");
2876 return 0;
2877 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002878 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002879 else
2880 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002881 lg2::error("Unrecognized chassis state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002882 throw std::invalid_argument("Unrecognized Transition Request");
2883 return 0;
2884 }
2885 resp = requested;
2886 return 1;
2887 });
Lei YU92caa4c2021-02-23 16:59:25 +08002888 chassisIface->register_property("CurrentPowerState",
2889 std::string(getChassisState(powerState)));
2890 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002891
Lei YU92caa4c2021-02-23 16:59:25 +08002892 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002893
Vijay Khemka04175c22020-10-09 14:28:11 -07002894#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002895 // Chassis System Service
2896 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002897 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002898
2899 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002900 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002901 "/xyz/openbmc_project/state/chassis_system0",
2902 "xyz.openbmc_project.State.Chassis");
2903
Lei YU92caa4c2021-02-23 16:59:25 +08002904 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002905 "RequestedPowerTransition",
2906 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
2907 [](const std::string& requested, std::string& resp) {
2908 if (requested ==
2909 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2910 {
Lei YU92caa4c2021-02-23 16:59:25 +08002911 systemReset();
2912 addRestartCause(RestartCause::command);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002913 }
2914 else
2915 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002916 lg2::error(
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002917 "Unrecognized chassis system state transition request.");
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002918 throw std::invalid_argument("Unrecognized Transition Request");
2919 return 0;
2920 }
2921 resp = requested;
2922 return 1;
2923 });
Lei YU92caa4c2021-02-23 16:59:25 +08002924 chassisSysIface->register_property(
2925 "CurrentPowerState", std::string(getChassisState(powerState)));
2926 chassisSysIface->register_property("LastStateChangeTime",
2927 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002928
Lei YU92caa4c2021-02-23 16:59:25 +08002929 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002930
Naveen Moses117c34e2021-05-26 20:10:51 +05302931 if (!slotPowerConfig.lineName.empty())
2932 {
2933 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
2934 {
2935 return -1;
2936 }
2937
2938 slotPowerState = SlotPowerState::off;
2939 if (slotPowerLine.get_value() > 0)
2940 {
2941 slotPowerState = SlotPowerState::on;
2942 }
2943
2944 chassisSlotIface = chassisSysServer.add_interface(
2945 "/xyz/openbmc_project/state/chassis_system" + node,
2946 "xyz.openbmc_project.State.Chassis");
2947 chassisSlotIface->register_property(
2948 "RequestedPowerTransition",
2949 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
2950 [](const std::string& requested, std::string& resp) {
2951 if (requested ==
2952 "xyz.openbmc_project.State.Chassis.Transition.On")
2953 {
2954 slotPowerOn();
2955 }
2956 else if (requested ==
2957 "xyz.openbmc_project.State.Chassis.Transition.Off")
2958 {
2959 slotPowerOff();
2960 }
Jason M. Bills418ce112021-09-08 15:15:05 -07002961 else if (
2962 requested ==
2963 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
Naveen Moses117c34e2021-05-26 20:10:51 +05302964 {
2965 slotPowerCycle();
2966 }
2967 else
2968 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002969 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002970 "Unrecognized chassis system state transition request.\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05302971 throw std::invalid_argument(
2972 "Unrecognized Transition Request");
2973 return 0;
2974 }
2975 resp = requested;
2976 return 1;
2977 });
2978 chassisSlotIface->register_property(
2979 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
2980 chassisSlotIface->register_property("LastStateChangeTime",
2981 getCurrentTimeMs());
2982 chassisSlotIface->initialize();
2983 }
2984#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002985 // Buttons Service
2986 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002987 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002988
Priyatharshan P70120512020-09-16 18:47:20 +05302989 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08002990 {
Priyatharshan P70120512020-09-16 18:47:20 +05302991 // Power Button Interface
2992 power_control::powerButtonIface = buttonsServer.add_interface(
2993 "/xyz/openbmc_project/chassis/buttons/power",
2994 "xyz.openbmc_project.Chassis.Buttons");
2995
2996 powerButtonIface->register_property(
2997 "ButtonMasked", false, [](const bool requested, bool& current) {
2998 if (requested)
2999 {
3000 if (powerButtonMask)
3001 {
3002 return 1;
3003 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003004 if (!setGPIOOutput(powerOutConfig.lineName,
3005 !powerOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303006 powerButtonMask))
3007 {
3008 throw std::runtime_error("Failed to request GPIO");
3009 return 0;
3010 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003011 lg2::info("Power Button Masked.");
Priyatharshan P70120512020-09-16 18:47:20 +05303012 }
3013 else
3014 {
3015 if (!powerButtonMask)
3016 {
3017 return 1;
3018 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003019 lg2::info("Power Button Un-masked");
Priyatharshan P70120512020-09-16 18:47:20 +05303020 powerButtonMask.reset();
3021 }
3022 // Update the mask setting
3023 current = requested;
3024 return 1;
3025 });
3026
3027 // Check power button state
3028 bool powerButtonPressed;
3029 if (powerButtonConfig.type == ConfigType::GPIO)
3030 {
3031 powerButtonPressed = powerButtonLine.get_value() == 0;
3032 }
3033 else
3034 {
3035 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3036 }
3037
3038 powerButtonIface->register_property("ButtonPressed",
3039 powerButtonPressed);
3040
3041 powerButtonIface->initialize();
3042 }
3043
3044 if (!resetButtonConfig.lineName.empty())
3045 {
3046 // Reset Button Interface
3047
Lei YU92caa4c2021-02-23 16:59:25 +08003048 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003049 "/xyz/openbmc_project/chassis/buttons/reset",
3050 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003051
Lei YU92caa4c2021-02-23 16:59:25 +08003052 resetButtonIface->register_property(
John Wang6c090072020-09-30 13:32:16 +08003053 "ButtonMasked", false, [](const bool requested, bool& current) {
3054 if (requested)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003055 {
Lei YU92caa4c2021-02-23 16:59:25 +08003056 if (resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003057 {
3058 return 1;
3059 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003060 if (!setGPIOOutput(resetOutConfig.lineName,
3061 !resetOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303062 resetButtonMask))
John Wang6c090072020-09-30 13:32:16 +08003063 {
3064 throw std::runtime_error("Failed to request GPIO");
3065 return 0;
3066 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003067 lg2::info("Reset Button Masked.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003068 }
John Wang6c090072020-09-30 13:32:16 +08003069 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003070 {
Lei YU92caa4c2021-02-23 16:59:25 +08003071 if (!resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003072 {
3073 return 1;
3074 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003075 lg2::info("Reset Button Un-masked");
Lei YU92caa4c2021-02-23 16:59:25 +08003076 resetButtonMask.reset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003077 }
John Wang6c090072020-09-30 13:32:16 +08003078 // Update the mask setting
3079 current = requested;
3080 return 1;
3081 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003082
John Wang6c090072020-09-30 13:32:16 +08003083 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303084 bool resetButtonPressed;
3085 if (resetButtonConfig.type == ConfigType::GPIO)
3086 {
3087 resetButtonPressed = resetButtonLine.get_value() == 0;
3088 }
3089 else
3090 {
3091 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3092 }
3093
Lei YU92caa4c2021-02-23 16:59:25 +08003094 resetButtonIface->register_property("ButtonPressed",
3095 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003096
Lei YU92caa4c2021-02-23 16:59:25 +08003097 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003098 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003099
Lei YU92caa4c2021-02-23 16:59:25 +08003100 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003101 {
3102 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003103 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003104 "/xyz/openbmc_project/chassis/buttons/nmi",
3105 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003106
Lei YU92caa4c2021-02-23 16:59:25 +08003107 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003108 "ButtonMasked", false, [](const bool requested, bool& current) {
Lei YU92caa4c2021-02-23 16:59:25 +08003109 if (nmiButtonMasked == requested)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003110 {
3111 // NMI button mask is already set as requested, so no change
3112 return 1;
3113 }
3114 if (requested)
3115 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003116 lg2::info("NMI Button Masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003117 nmiButtonMasked = true;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003118 }
3119 else
3120 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003121 lg2::info("NMI Button Un-masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003122 nmiButtonMasked = false;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003123 }
3124 // Update the mask setting
Lei YU92caa4c2021-02-23 16:59:25 +08003125 current = nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003126 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003127 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003128
Vijay Khemka33a532d2019-11-14 16:50:35 -08003129 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303130 bool nmiButtonPressed;
3131 if (nmiButtonConfig.type == ConfigType::GPIO)
3132 {
3133 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3134 }
3135 else
3136 {
3137 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3138 }
3139
Lei YU92caa4c2021-02-23 16:59:25 +08003140 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003141
Lei YU92caa4c2021-02-23 16:59:25 +08003142 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003143 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003144
Lei YU92caa4c2021-02-23 16:59:25 +08003145 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003146 {
3147 // NMI out Service
3148 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003149 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003150
Vijay Khemka33a532d2019-11-14 16:50:35 -08003151 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303152 nmiOutIface = nmiOutServer.add_interface(
3153 "/xyz/openbmc_project/control/host" + node + "/nmi",
3154 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003155 nmiOutIface->register_method("NMI", nmiReset);
3156 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003157 }
Chen Yugang174ec662019-08-19 19:58:49 +08003158
Lei YU92caa4c2021-02-23 16:59:25 +08003159 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003160 {
3161 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003162 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003163 "/xyz/openbmc_project/chassis/buttons/id",
3164 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003165
Vijay Khemka33a532d2019-11-14 16:50:35 -08003166 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303167 bool idButtonPressed;
3168 if (idButtonConfig.type == ConfigType::GPIO)
3169 {
3170 idButtonPressed = idButtonLine.get_value() == 0;
3171 }
3172 else
3173 {
3174 idButtonPressed = getProperty(idButtonConfig) == 0;
3175 }
3176
Lei YU92caa4c2021-02-23 16:59:25 +08003177 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003178
Lei YU92caa4c2021-02-23 16:59:25 +08003179 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003180 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003181
3182 // OS State Service
3183 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003184 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003185
3186 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003187 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003188 "/xyz/openbmc_project/state/os",
3189 "xyz.openbmc_project.State.OperatingSystem.Status");
3190
3191 // Get the initial OS state based on POST complete
3192 // 0: Asserted, OS state is "Standby" (ready to boot)
3193 // 1: De-Asserted, OS state is "Inactive"
Priyatharshan P70120512020-09-16 18:47:20 +05303194 std::string osState;
3195 if (postCompleteConfig.type == ConfigType::GPIO)
3196 {
3197 osState = postCompleteLine.get_value() > 0 ? "Inactive" : "Standby";
3198 }
3199 else
3200 {
3201 osState = getProperty(postCompleteConfig) > 0 ? "Inactive" : "Standby";
3202 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003203
Lei YU92caa4c2021-02-23 16:59:25 +08003204 osIface->register_property("OperatingSystemState", std::string(osState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003205
Lei YU92caa4c2021-02-23 16:59:25 +08003206 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003207
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003208 // Restart Cause Service
3209 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003210 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003211
3212 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003213 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303214 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003215 "xyz.openbmc_project.Control.Host.RestartCause");
3216
Lei YU92caa4c2021-02-23 16:59:25 +08003217 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003218 "RestartCause",
3219 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3220
Lei YU92caa4c2021-02-23 16:59:25 +08003221 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003222 "RequestedRestartCause",
3223 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3224 [](const std::string& requested, std::string& resp) {
3225 if (requested ==
3226 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3227 {
Lei YU92caa4c2021-02-23 16:59:25 +08003228 addRestartCause(RestartCause::watchdog);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003229 }
3230 else
3231 {
3232 throw std::invalid_argument(
3233 "Unrecognized RestartCause Request");
3234 return 0;
3235 }
3236
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003237 lg2::info("RestartCause requested: {RESTART_CAUSE}",
3238 "RESTART_CAUSE", requested);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003239 resp = requested;
3240 return 1;
3241 });
3242
Lei YU92caa4c2021-02-23 16:59:25 +08003243 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003244
Lei YU92caa4c2021-02-23 16:59:25 +08003245 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003246
Lei YU92caa4c2021-02-23 16:59:25 +08003247 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003248
3249 return 0;
3250}