blob: 9f5be280df999a65b2f689de1d50e507a452109f [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*/
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +030016#include "power_control.hpp"
17
Ed Tanousf61ca6f2019-08-15 15:09:05 -070018#include <sys/sysinfo.h>
19#include <systemd/sd-journal.h>
20
Jason M. Billse63dea02020-08-27 12:07:35 -070021#include <boost/asio/io_service.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070022#include <boost/asio/posix/stream_descriptor.hpp>
Jason M. Billse63dea02020-08-27 12:07:35 -070023#include <boost/asio/steady_timer.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070024#include <boost/container/flat_map.hpp>
Jason M. Bills7d4aaac2019-09-19 14:03:44 -070025#include <boost/container/flat_set.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070026#include <gpiod.hpp>
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053027#include <nlohmann/json.hpp>
Jason M. Billsc46ebb42021-11-10 11:41:31 -080028#include <phosphor-logging/lg2.hpp>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070029#include <sdbusplus/asio/object_server.hpp>
Vijay Khemka2b6f4422020-05-29 11:13:23 -070030
31#include <filesystem>
32#include <fstream>
Ed Tanousf61ca6f2019-08-15 15:09:05 -070033#include <string_view>
34
35namespace power_control
36{
37static boost::asio::io_service io;
38std::shared_ptr<sdbusplus::asio::connection> conn;
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +030039PersistentState appState;
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +030040PowerRestoreController powerRestore(io);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053041
42static std::string node = "0";
Andrei Kartashev3efcf372021-12-29 15:32:17 +030043static const std::string appName = "power-control";
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053044
Priyatharshan P70120512020-09-16 18:47:20 +053045enum class DbusConfigType
46{
47 name = 1,
48 path,
49 interface,
50 property
51};
52boost::container::flat_map<DbusConfigType, std::string> dbusParams = {
53 {DbusConfigType::name, "DbusName"},
54 {DbusConfigType::path, "Path"},
55 {DbusConfigType::interface, "Interface"},
56 {DbusConfigType::property, "Property"}};
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +053057
Priyatharshan P70120512020-09-16 18:47:20 +053058enum class ConfigType
59{
60 GPIO = 1,
61 DBUS
62};
63
64struct ConfigData
65{
66 std::string name;
67 std::string lineName;
68 std::string dbusName;
69 std::string path;
70 std::string interface;
Jean-Marie Verdun50937e72021-08-31 09:15:49 -070071 bool polarity;
Priyatharshan P70120512020-09-16 18:47:20 +053072 ConfigType type;
73};
74
75static ConfigData powerOutConfig;
76static ConfigData powerOkConfig;
77static ConfigData resetOutConfig;
78static ConfigData nmiOutConfig;
79static ConfigData sioPwrGoodConfig;
80static ConfigData sioOnControlConfig;
81static ConfigData sioS5Config;
82static ConfigData postCompleteConfig;
83static ConfigData powerButtonConfig;
84static ConfigData resetButtonConfig;
85static ConfigData idButtonConfig;
86static ConfigData nmiButtonConfig;
Naveen Moses117c34e2021-05-26 20:10:51 +053087static ConfigData slotPowerConfig;
88
Priyatharshan P70120512020-09-16 18:47:20 +053089// map for storing list of gpio parameters whose config are to be read from x86
90// power control json config
91boost::container::flat_map<std::string, ConfigData*> powerSignalMap = {
92 {"PowerOut", &powerOutConfig},
93 {"PowerOk", &powerOkConfig},
94 {"ResetOut", &resetOutConfig},
95 {"NMIOut", &nmiOutConfig},
96 {"SioPowerGood", &sioPwrGoodConfig},
97 {"SioOnControl", &sioOnControlConfig},
98 {"SIOS5", &sioS5Config},
99 {"PostComplete", &postCompleteConfig},
100 {"PowerButton", &powerButtonConfig},
101 {"ResetButton", &resetButtonConfig},
102 {"IdButton", &idButtonConfig},
Naveen Moses117c34e2021-05-26 20:10:51 +0530103 {"NMIButton", &nmiButtonConfig},
104 {"SlotPower", &slotPowerConfig}};
Priyatharshan P70120512020-09-16 18:47:20 +0530105
106static std::string hostDbusName = "xyz.openbmc_project.State.Host";
107static std::string chassisDbusName = "xyz.openbmc_project.State.Chassis";
108static std::string osDbusName = "xyz.openbmc_project.State.OperatingSystem";
109static std::string buttonDbusName = "xyz.openbmc_project.Chassis.Buttons";
110static std::string nmiDbusName = "xyz.openbmc_project.Control.Host.NMI";
111static std::string rstCauseDbusName =
112 "xyz.openbmc_project.Control.Host.RestartCause";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700113static std::shared_ptr<sdbusplus::asio::dbus_interface> hostIface;
114static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700115#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -0700116static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSysIface;
Naveen Moses117c34e2021-05-26 20:10:51 +0530117static std::shared_ptr<sdbusplus::asio::dbus_interface> chassisSlotIface;
Vijay Khemka04175c22020-10-09 14:28:11 -0700118#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700119static std::shared_ptr<sdbusplus::asio::dbus_interface> powerButtonIface;
120static std::shared_ptr<sdbusplus::asio::dbus_interface> resetButtonIface;
121static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiButtonIface;
122static std::shared_ptr<sdbusplus::asio::dbus_interface> osIface;
123static std::shared_ptr<sdbusplus::asio::dbus_interface> idButtonIface;
Chen Yugang174ec662019-08-19 19:58:49 +0800124static std::shared_ptr<sdbusplus::asio::dbus_interface> nmiOutIface;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700125static std::shared_ptr<sdbusplus::asio::dbus_interface> restartCauseIface;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700126
127static gpiod::line powerButtonMask;
128static gpiod::line resetButtonMask;
129static bool nmiButtonMasked = false;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700130
Priyatharshan P70120512020-09-16 18:47:20 +0530131// This map contains all timer values that are to be read from json config
132boost::container::flat_map<std::string, int> TimerMap = {
Jason M. Billsaeefe042021-09-08 14:56:11 -0700133 {"PowerPulseMs", 200},
134 {"ForceOffPulseMs", 15000},
135 {"ResetPulseMs", 500},
136 {"PowerCycleMs", 5000},
137 {"SioPowerGoodWatchdogMs", 1000},
138 {"PsPowerOKWatchdogMs", 8000},
139 {"GracefulPowerOffS", (5 * 60)},
140 {"WarmResetCheckMs", 500},
141 {"PowerOffSaveMs", 7000},
142 {"SlotPowerCycleMs", 200}};
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700143
144static bool nmiEnabled = true;
Priyatharshan P19c47a32020-08-12 18:16:43 +0530145static bool sioEnabled = true;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700146
147// Timers
148// Time holding GPIOs asserted
149static boost::asio::steady_timer gpioAssertTimer(io);
150// Time between off and on during a power cycle
151static boost::asio::steady_timer powerCycleTimer(io);
152// Time OS gracefully powering off
153static boost::asio::steady_timer gracefulPowerOffTimer(io);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700154// Time the warm reset check
155static boost::asio::steady_timer warmResetCheckTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700156// Time power supply power OK assertion on power-on
157static boost::asio::steady_timer psPowerOKWatchdogTimer(io);
158// Time SIO power good assertion on power-on
159static boost::asio::steady_timer sioPowerGoodWatchdogTimer(io);
160// Time power-off state save for power loss tracking
161static boost::asio::steady_timer powerStateSaveTimer(io);
162// POH timer
163static boost::asio::steady_timer pohCounterTimer(io);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700164// Time when to allow restart cause updates
165static boost::asio::steady_timer restartCauseTimer(io);
Naveen Moses117c34e2021-05-26 20:10:51 +0530166static boost::asio::steady_timer slotPowerCycleTimer(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700167
168// GPIO Lines and Event Descriptors
169static gpiod::line psPowerOKLine;
170static boost::asio::posix::stream_descriptor psPowerOKEvent(io);
171static gpiod::line sioPowerGoodLine;
172static boost::asio::posix::stream_descriptor sioPowerGoodEvent(io);
173static gpiod::line sioOnControlLine;
174static boost::asio::posix::stream_descriptor sioOnControlEvent(io);
175static gpiod::line sioS5Line;
176static boost::asio::posix::stream_descriptor sioS5Event(io);
177static gpiod::line powerButtonLine;
178static boost::asio::posix::stream_descriptor powerButtonEvent(io);
179static gpiod::line resetButtonLine;
180static boost::asio::posix::stream_descriptor resetButtonEvent(io);
181static gpiod::line nmiButtonLine;
182static boost::asio::posix::stream_descriptor nmiButtonEvent(io);
183static gpiod::line idButtonLine;
184static boost::asio::posix::stream_descriptor idButtonEvent(io);
185static gpiod::line postCompleteLine;
186static boost::asio::posix::stream_descriptor postCompleteEvent(io);
187static gpiod::line nmiOutLine;
Naveen Moses117c34e2021-05-26 20:10:51 +0530188static gpiod::line slotPowerLine;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700189
190static constexpr uint8_t beepPowerFail = 8;
191
192static void beep(const uint8_t& beepPriority)
193{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800194 lg2::info("Beep with priority: {BEEP_PRIORITY}", "BEEP_PRIORITY",
195 beepPriority);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700196
197 conn->async_method_call(
198 [](boost::system::error_code ec) {
199 if (ec)
200 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800201 lg2::error(
202 "beep returned error with async_method_call (ec = {ERROR_MSG})",
203 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700204 return;
205 }
206 },
207 "xyz.openbmc_project.BeepCode", "/xyz/openbmc_project/BeepCode",
208 "xyz.openbmc_project.BeepCode", "Beep", uint8_t(beepPriority));
209}
210
Tim Lee86239182021-12-23 11:46:01 +0800211enum class OperatingSystemStateStage
212{
213 Inactive,
214 Standby,
215};
216static constexpr std::string_view
217 getOperatingSystemStateStage(const OperatingSystemStateStage stage)
218{
219 switch (stage)
220 {
221 case OperatingSystemStateStage::Inactive:
222 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
223 break;
224 case OperatingSystemStateStage::Standby:
225 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Standby";
226 break;
227 default:
228 return "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
229 break;
230 }
231};
232static void setOperatingSystemState(const OperatingSystemStateStage stage)
233{
234 osIface->set_property("OperatingSystemState",
235 std::string(getOperatingSystemStateStage(stage)));
236
237 lg2::info("Moving os state to {STATE} stage", "STATE",
238 getOperatingSystemStateStage(stage));
239}
240
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700241enum class PowerState
242{
243 on,
244 waitForPSPowerOK,
245 waitForSIOPowerGood,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700246 off,
247 transitionToOff,
248 gracefulTransitionToOff,
249 cycleOff,
250 transitionToCycleOff,
251 gracefulTransitionToCycleOff,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700252 checkForWarmReset,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700253};
254static PowerState powerState;
255static std::string getPowerStateName(PowerState state)
256{
257 switch (state)
258 {
259 case PowerState::on:
260 return "On";
261 break;
262 case PowerState::waitForPSPowerOK:
263 return "Wait for Power Supply Power OK";
264 break;
265 case PowerState::waitForSIOPowerGood:
266 return "Wait for SIO Power Good";
267 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700268 case PowerState::off:
269 return "Off";
270 break;
271 case PowerState::transitionToOff:
272 return "Transition to Off";
273 break;
274 case PowerState::gracefulTransitionToOff:
275 return "Graceful Transition to Off";
276 break;
277 case PowerState::cycleOff:
278 return "Power Cycle Off";
279 break;
280 case PowerState::transitionToCycleOff:
281 return "Transition to Power Cycle Off";
282 break;
283 case PowerState::gracefulTransitionToCycleOff:
284 return "Graceful Transition to Power Cycle Off";
285 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700286 case PowerState::checkForWarmReset:
287 return "Check for Warm Reset";
288 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700289 default:
290 return "unknown state: " + std::to_string(static_cast<int>(state));
291 break;
292 }
293}
294static void logStateTransition(const PowerState state)
295{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800296 lg2::info("Host{HOST}: Moving to \"{STATE}\" state", "HOST", node, "STATE",
297 getPowerStateName(state));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700298}
299
300enum class Event
301{
302 psPowerOKAssert,
303 psPowerOKDeAssert,
304 sioPowerGoodAssert,
305 sioPowerGoodDeAssert,
306 sioS5Assert,
307 sioS5DeAssert,
Jason M. Billsfb957332021-01-28 13:18:46 -0800308 pltRstAssert,
309 pltRstDeAssert,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700310 postCompleteAssert,
311 postCompleteDeAssert,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700312 powerButtonPressed,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700313 resetButtonPressed,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700314 powerCycleTimerExpired,
315 psPowerOKWatchdogTimerExpired,
316 sioPowerGoodWatchdogTimerExpired,
317 gracefulPowerOffTimerExpired,
318 powerOnRequest,
319 powerOffRequest,
320 powerCycleRequest,
321 resetRequest,
322 gracefulPowerOffRequest,
323 gracefulPowerCycleRequest,
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700324 warmResetDetected,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700325};
326static std::string getEventName(Event event)
327{
328 switch (event)
329 {
330 case Event::psPowerOKAssert:
331 return "power supply power OK assert";
332 break;
333 case Event::psPowerOKDeAssert:
334 return "power supply power OK de-assert";
335 break;
336 case Event::sioPowerGoodAssert:
337 return "SIO power good assert";
338 break;
339 case Event::sioPowerGoodDeAssert:
340 return "SIO power good de-assert";
341 break;
342 case Event::sioS5Assert:
343 return "SIO S5 assert";
344 break;
345 case Event::sioS5DeAssert:
346 return "SIO S5 de-assert";
347 break;
Jason M. Billsfb957332021-01-28 13:18:46 -0800348 case Event::pltRstAssert:
349 return "PLT_RST assert";
350 break;
351 case Event::pltRstDeAssert:
352 return "PLT_RST de-assert";
353 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700354 case Event::postCompleteAssert:
355 return "POST Complete assert";
356 break;
357 case Event::postCompleteDeAssert:
358 return "POST Complete de-assert";
359 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700360 case Event::powerButtonPressed:
361 return "power button pressed";
362 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700363 case Event::resetButtonPressed:
364 return "reset button pressed";
365 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700366 case Event::powerCycleTimerExpired:
367 return "power cycle timer expired";
368 break;
369 case Event::psPowerOKWatchdogTimerExpired:
370 return "power supply power OK watchdog timer expired";
371 break;
372 case Event::sioPowerGoodWatchdogTimerExpired:
373 return "SIO power good watchdog timer expired";
374 break;
375 case Event::gracefulPowerOffTimerExpired:
376 return "graceful power-off timer expired";
377 break;
378 case Event::powerOnRequest:
379 return "power-on request";
380 break;
381 case Event::powerOffRequest:
382 return "power-off request";
383 break;
384 case Event::powerCycleRequest:
385 return "power-cycle request";
386 break;
387 case Event::resetRequest:
388 return "reset request";
389 break;
390 case Event::gracefulPowerOffRequest:
391 return "graceful power-off request";
392 break;
393 case Event::gracefulPowerCycleRequest:
394 return "graceful power-cycle request";
395 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700396 case Event::warmResetDetected:
397 return "warm reset detected";
398 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700399 default:
400 return "unknown event: " + std::to_string(static_cast<int>(event));
401 break;
402 }
403}
404static void logEvent(const std::string_view stateHandler, const Event event)
405{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800406 lg2::info("{STATE_HANDLER}: {EVENT} event received", "STATE_HANDLER",
407 stateHandler, "EVENT", getEventName(event));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700408}
409
410// Power state handlers
411static void powerStateOn(const Event event);
412static void powerStateWaitForPSPowerOK(const Event event);
413static void powerStateWaitForSIOPowerGood(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700414static void powerStateOff(const Event event);
415static void powerStateTransitionToOff(const Event event);
416static void powerStateGracefulTransitionToOff(const Event event);
417static void powerStateCycleOff(const Event event);
418static void powerStateTransitionToCycleOff(const Event event);
419static void powerStateGracefulTransitionToCycleOff(const Event event);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700420static void powerStateCheckForWarmReset(const Event event);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700421
422static std::function<void(const Event)> getPowerStateHandler(PowerState state)
423{
424 switch (state)
425 {
426 case PowerState::on:
427 return powerStateOn;
428 break;
429 case PowerState::waitForPSPowerOK:
430 return powerStateWaitForPSPowerOK;
431 break;
432 case PowerState::waitForSIOPowerGood:
433 return powerStateWaitForSIOPowerGood;
434 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700435 case PowerState::off:
436 return powerStateOff;
437 break;
438 case PowerState::transitionToOff:
439 return powerStateTransitionToOff;
440 break;
441 case PowerState::gracefulTransitionToOff:
442 return powerStateGracefulTransitionToOff;
443 break;
444 case PowerState::cycleOff:
445 return powerStateCycleOff;
446 break;
447 case PowerState::transitionToCycleOff:
448 return powerStateTransitionToCycleOff;
449 break;
450 case PowerState::gracefulTransitionToCycleOff:
451 return powerStateGracefulTransitionToCycleOff;
452 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700453 case PowerState::checkForWarmReset:
454 return powerStateCheckForWarmReset;
455 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700456 default:
Zev Weiss047bcb52020-08-20 21:28:11 +0000457 return nullptr;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700458 break;
459 }
460};
461
462static void sendPowerControlEvent(const Event event)
463{
464 std::function<void(const Event)> handler = getPowerStateHandler(powerState);
465 if (handler == nullptr)
466 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800467 lg2::error("Failed to find handler for power state: {STATE}", "STATE",
468 static_cast<int>(powerState));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700469 return;
470 }
471 handler(event);
472}
473
474static uint64_t getCurrentTimeMs()
475{
476 struct timespec time = {};
477
478 if (clock_gettime(CLOCK_REALTIME, &time) < 0)
479 {
480 return 0;
481 }
482 uint64_t currentTimeMs = static_cast<uint64_t>(time.tv_sec) * 1000;
483 currentTimeMs += static_cast<uint64_t>(time.tv_nsec) / 1000 / 1000;
484
485 return currentTimeMs;
486}
487
488static constexpr std::string_view getHostState(const PowerState state)
489{
490 switch (state)
491 {
492 case PowerState::on:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700493 case PowerState::gracefulTransitionToOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700494 case PowerState::gracefulTransitionToCycleOff:
495 return "xyz.openbmc_project.State.Host.HostState.Running";
496 break;
497 case PowerState::waitForPSPowerOK:
498 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700499 case PowerState::off:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700500 case PowerState::transitionToOff:
501 case PowerState::transitionToCycleOff:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700502 case PowerState::cycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700503 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700504 return "xyz.openbmc_project.State.Host.HostState.Off";
505 break;
506 default:
507 return "";
508 break;
509 }
510};
511static constexpr std::string_view getChassisState(const PowerState state)
512{
513 switch (state)
514 {
515 case PowerState::on:
516 case PowerState::transitionToOff:
517 case PowerState::gracefulTransitionToOff:
518 case PowerState::transitionToCycleOff:
519 case PowerState::gracefulTransitionToCycleOff:
Jason M. Billse9a9e2d2019-08-08 14:01:19 -0700520 case PowerState::checkForWarmReset:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700521 return "xyz.openbmc_project.State.Chassis.PowerState.On";
522 break;
523 case PowerState::waitForPSPowerOK:
524 case PowerState::waitForSIOPowerGood:
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700525 case PowerState::off:
526 case PowerState::cycleOff:
527 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
528 break;
529 default:
530 return "";
531 break;
532 }
533};
Naveen Moses117c34e2021-05-26 20:10:51 +0530534#ifdef CHASSIS_SYSTEM_RESET
535enum class SlotPowerState
536{
537 on,
538 off,
539};
540static SlotPowerState slotPowerState;
541static constexpr std::string_view getSlotState(const SlotPowerState state)
542{
543 switch (state)
544 {
545 case SlotPowerState::on:
546 return "xyz.openbmc_project.State.Chassis.PowerState.On";
547 break;
548 case SlotPowerState::off:
549 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
550 break;
551 default:
552 return "";
553 break;
554 }
555};
556static void setSlotPowerState(const SlotPowerState state)
557{
558 slotPowerState = state;
559 chassisSlotIface->set_property("CurrentPowerState",
560 std::string(getSlotState(slotPowerState)));
561 chassisSlotIface->set_property("LastStateChangeTime", getCurrentTimeMs());
562}
563#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700564static void savePowerState(const PowerState state)
565{
566 powerStateSaveTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -0700567 std::chrono::milliseconds(TimerMap["PowerOffSaveMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700568 powerStateSaveTimer.async_wait([state](const boost::system::error_code ec) {
569 if (ec)
570 {
571 // operation_aborted is expected if timer is canceled before
572 // completion.
573 if (ec != boost::asio::error::operation_aborted)
574 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800575 lg2::error("Power-state save async_wait failed: {ERROR_MSG}",
576 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700577 }
578 return;
579 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300580 appState.set(PersistentState::Params::PowerState,
581 std::string{getChassisState(state)});
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700582 });
583}
584static void setPowerState(const PowerState state)
585{
586 powerState = state;
587 logStateTransition(state);
588
589 hostIface->set_property("CurrentHostState",
590 std::string(getHostState(powerState)));
591
592 chassisIface->set_property("CurrentPowerState",
593 std::string(getChassisState(powerState)));
594 chassisIface->set_property("LastStateChangeTime", getCurrentTimeMs());
595
596 // Save the power state for the restore policy
597 savePowerState(state);
598}
599
600enum class RestartCause
601{
602 command,
603 resetButton,
604 powerButton,
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700605 watchdog,
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700606 powerPolicyOn,
607 powerPolicyRestore,
608 softReset,
609};
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700610static boost::container::flat_set<RestartCause> causeSet;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700611static std::string getRestartCause(RestartCause cause)
612{
613 switch (cause)
614 {
615 case RestartCause::command:
616 return "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand";
617 break;
618 case RestartCause::resetButton:
619 return "xyz.openbmc_project.State.Host.RestartCause.ResetButton";
620 break;
621 case RestartCause::powerButton:
622 return "xyz.openbmc_project.State.Host.RestartCause.PowerButton";
623 break;
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700624 case RestartCause::watchdog:
625 return "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer";
626 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700627 case RestartCause::powerPolicyOn:
Jason M. Bills418ce112021-09-08 15:15:05 -0700628 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyAlwaysOn";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700629 break;
630 case RestartCause::powerPolicyRestore:
Jason M. Bills418ce112021-09-08 15:15:05 -0700631 return "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyPreviousState";
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700632 break;
633 case RestartCause::softReset:
634 return "xyz.openbmc_project.State.Host.RestartCause.SoftReset";
635 break;
636 default:
637 return "xyz.openbmc_project.State.Host.RestartCause.Unknown";
638 break;
639 }
640}
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700641static void addRestartCause(const RestartCause cause)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700642{
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700643 // Add this to the set of causes for this restart
644 causeSet.insert(cause);
645}
646static void clearRestartCause()
647{
648 // Clear the set for the next restart
649 causeSet.clear();
650}
651static void setRestartCauseProperty(const std::string& cause)
652{
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800653 lg2::info("RestartCause set to {RESTART_CAUSE}", "RESTART_CAUSE", cause);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700654 restartCauseIface->set_property("RestartCause", cause);
655}
Rashmi RV89f61312020-01-22 15:41:50 +0530656
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300657#ifdef USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +0530658static void resetACBootProperty()
659{
660 if ((causeSet.contains(RestartCause::command)) ||
661 (causeSet.contains(RestartCause::softReset)))
662 {
663 conn->async_method_call(
664 [](boost::system::error_code ec) {
665 if (ec)
666 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800667 lg2::error("failed to reset ACBoot property");
Rashmi RV89f61312020-01-22 15:41:50 +0530668 }
669 },
670 "xyz.openbmc_project.Settings",
671 "/xyz/openbmc_project/control/host0/ac_boot",
672 "org.freedesktop.DBus.Properties", "Set",
673 "xyz.openbmc_project.Common.ACBoot", "ACBoot",
674 std::variant<std::string>{"False"});
675 }
676}
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300677#endif // USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +0530678
Jason M. Bills7d4aaac2019-09-19 14:03:44 -0700679static void setRestartCause()
680{
681 // Determine the actual restart cause based on the set of causes
682 std::string restartCause =
683 "xyz.openbmc_project.State.Host.RestartCause.Unknown";
684 if (causeSet.contains(RestartCause::watchdog))
685 {
686 restartCause = getRestartCause(RestartCause::watchdog);
687 }
688 else if (causeSet.contains(RestartCause::command))
689 {
690 restartCause = getRestartCause(RestartCause::command);
691 }
692 else if (causeSet.contains(RestartCause::resetButton))
693 {
694 restartCause = getRestartCause(RestartCause::resetButton);
695 }
696 else if (causeSet.contains(RestartCause::powerButton))
697 {
698 restartCause = getRestartCause(RestartCause::powerButton);
699 }
700 else if (causeSet.contains(RestartCause::powerPolicyOn))
701 {
702 restartCause = getRestartCause(RestartCause::powerPolicyOn);
703 }
704 else if (causeSet.contains(RestartCause::powerPolicyRestore))
705 {
706 restartCause = getRestartCause(RestartCause::powerPolicyRestore);
707 }
708 else if (causeSet.contains(RestartCause::softReset))
709 {
710 restartCause = getRestartCause(RestartCause::softReset);
711 }
712
713 setRestartCauseProperty(restartCause);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700714}
715
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700716static void systemPowerGoodFailedLog()
717{
718 sd_journal_send(
719 "MESSAGE=PowerControl: system power good failed to assert (VR failure)",
720 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
721 "OpenBMC.0.1.SystemPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700722 TimerMap["SioPowerGoodWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700723}
724
725static void psPowerOKFailedLog()
726{
727 sd_journal_send(
728 "MESSAGE=PowerControl: power supply power good failed to assert",
729 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
730 "OpenBMC.0.1.PowerSupplyPowerGoodFailed", "REDFISH_MESSAGE_ARGS=%d",
Jason M. Billsaeefe042021-09-08 14:56:11 -0700731 TimerMap["PsPowerOKWatchdogMs"], NULL);
Jason M. Bills6c2ad362019-08-01 16:53:35 -0700732}
733
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700734static void powerRestorePolicyLog()
735{
736 sd_journal_send("MESSAGE=PowerControl: power restore policy applied",
737 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
738 "OpenBMC.0.1.PowerRestorePolicyApplied", NULL);
739}
740
741static void powerButtonPressLog()
742{
743 sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
744 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
745 "OpenBMC.0.1.PowerButtonPressed", NULL);
746}
747
748static void resetButtonPressLog()
749{
750 sd_journal_send("MESSAGE=PowerControl: reset button pressed", "PRIORITY=%i",
751 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
752 "OpenBMC.0.1.ResetButtonPressed", NULL);
753}
754
755static void nmiButtonPressLog()
756{
757 sd_journal_send("MESSAGE=PowerControl: NMI button pressed", "PRIORITY=%i",
758 LOG_INFO, "REDFISH_MESSAGE_ID=%s",
759 "OpenBMC.0.1.NMIButtonPressed", NULL);
760}
761
762static void nmiDiagIntLog()
763{
764 sd_journal_send("MESSAGE=PowerControl: NMI Diagnostic Interrupt",
765 "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
766 "OpenBMC.0.1.NMIDiagnosticInterrupt", NULL);
767}
768
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300769PersistentState::PersistentState()
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700770{
771 // create the power control directory if it doesn't exist
772 std::error_code ec;
773 if (!(std::filesystem::create_directories(powerControlDir, ec)))
774 {
775 if (ec.value() != 0)
776 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -0800777 lg2::error("failed to create {DIR_NAME}: {ERROR_MSG}", "DIR_NAME",
778 powerControlDir.string(), "ERROR_MSG", ec.message());
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300779 throw std::runtime_error("Failed to create state directory");
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700780 }
781 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300782
783 // read saved state, it's ok, if the file doesn't exists
784 std::ifstream appStateStream(powerControlDir / stateFile);
785 if (!appStateStream.is_open())
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700786 {
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300787 lg2::info("Cannot open state file \'{PATH}\'", "PATH",
788 std::string(powerControlDir / stateFile));
789 stateData = nlohmann::json({});
790 return;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700791 }
Andrei Kartashev50fe8ee2022-01-04 21:24:22 +0300792 try
793 {
794 appStateStream >> stateData;
795 if (stateData.is_discarded())
796 {
797 lg2::info("Cannot parse state file \'{PATH}\'", "PATH",
798 std::string(powerControlDir / stateFile));
799 stateData = nlohmann::json({});
800 return;
801 }
802 }
803 catch (const std::exception& ex)
804 {
805 lg2::info("Cannot read state file \'{PATH}\'", "PATH",
806 std::string(powerControlDir / stateFile));
807 stateData = nlohmann::json({});
808 return;
809 }
810}
811PersistentState::~PersistentState()
812{
813 saveState();
814}
815const std::string PersistentState::get(Params parameter)
816{
817 auto val = stateData.find(getName(parameter));
818 if (val != stateData.end())
819 {
820 return val->get<std::string>();
821 }
822 return getDefault(parameter);
823}
824void PersistentState::set(Params parameter, const std::string& value)
825{
826 stateData[getName(parameter)] = value;
827 saveState();
828}
829
830const std::string PersistentState::getName(const Params parameter)
831{
832 switch (parameter)
833 {
834 case Params::PowerState:
835 return "PowerState";
836 }
837 return "";
838}
839const std::string PersistentState::getDefault(const Params parameter)
840{
841 switch (parameter)
842 {
843 case Params::PowerState:
844 return "xyz.openbmc_project.State.Chassis.PowerState.Off";
845 }
846 return "";
847}
848void PersistentState::saveState()
849{
850 std::ofstream appStateStream(powerControlDir / stateFile, std::ios::trunc);
851 if (!appStateStream.is_open())
852 {
853 lg2::error("Cannot write state file \'{PATH}\'", "PATH",
854 std::string(powerControlDir / stateFile));
855 return;
856 }
857 appStateStream << stateData.dump(indentationSize);
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700858}
859
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300860static constexpr char const* setingsService = "xyz.openbmc_project.Settings";
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300861static constexpr char const* powerRestorePolicyIface =
862 "xyz.openbmc_project.Control.Power.RestorePolicy";
863#ifdef USE_ACBOOT
864static constexpr char const* powerACBootObject =
865 "/xyz/openbmc_project/control/host0/ac_boot";
866static constexpr char const* powerACBootIface =
867 "xyz.openbmc_project.Common.ACBoot";
868#endif // USE_ACBOOT
869
870namespace match_rules = sdbusplus::bus::match::rules;
871
872static int powerRestoreConfigHandler(sd_bus_message* m, void* context,
873 sd_bus_error*)
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700874{
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300875 if (context == nullptr || m == nullptr)
876 {
877 throw std::runtime_error("Invalid match");
878 }
Patrick Williams439b9c32022-07-22 19:26:53 -0500879 sdbusplus::message_t message(m);
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300880 PowerRestoreController* powerRestore =
881 static_cast<PowerRestoreController*>(context);
882
883 if (std::string(message.get_member()) == "InterfacesAdded")
884 {
885 sdbusplus::message::object_path path;
886 boost::container::flat_map<std::string, dbusPropertiesList> data;
887
888 message.read(path, data);
889
890 for (auto& [iface, properties] : data)
891 {
892 if ((iface == powerRestorePolicyIface)
893#ifdef USE_ACBOOT
894 || (iface == powerACBootIface)
895#endif // USE_ACBOOT
896 )
897 {
898 powerRestore->setProperties(properties);
899 }
900 }
901 }
902 else if (std::string(message.get_member()) == "PropertiesChanged")
903 {
904 std::string interfaceName;
905 dbusPropertiesList propertiesChanged;
906
907 message.read(interfaceName, propertiesChanged);
908
909 powerRestore->setProperties(propertiesChanged);
910 }
911 return 1;
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700912}
913
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300914void PowerRestoreController::run()
Ed Tanousf61ca6f2019-08-15 15:09:05 -0700915{
Karthikeyan Pasupathib38fe832022-07-19 19:53:38 +0530916 std::string powerRestorePolicyObject =
917 "/xyz/openbmc_project/control/host" + node + "/power_restore_policy";
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +0300918 powerRestorePolicyLog();
919 // this list only needs to be created once
920 if (matches.empty())
921 {
922 matches.emplace_back(
923 *conn,
924 match_rules::interfacesAdded() +
925 match_rules::argNpath(0, powerRestorePolicyObject) +
926 match_rules::sender(setingsService),
927 powerRestoreConfigHandler, this);
928#ifdef USE_ACBOOT
929 matches.emplace_back(*conn,
930 match_rules::interfacesAdded() +
931 match_rules::argNpath(0, powerACBootObject) +
932 match_rules::sender(setingsService),
933 powerRestoreConfigHandler, this);
934 matches.emplace_back(*conn,
935 match_rules::propertiesChanged(powerACBootObject,
936 powerACBootIface) +
937 match_rules::sender(setingsService),
938 powerRestoreConfigHandler, this);
939#endif // USE_ACBOOT
940 }
941
942 // Check if it's already on DBus
943 conn->async_method_call(
944 [this](boost::system::error_code ec,
945 const dbusPropertiesList properties) {
946 if (ec)
947 {
948 return;
949 }
950 setProperties(properties);
951 },
952 setingsService, powerRestorePolicyObject,
953 "org.freedesktop.DBus.Properties", "GetAll", powerRestorePolicyIface);
954
955#ifdef USE_ACBOOT
956 // Check if it's already on DBus
957 conn->async_method_call(
958 [this](boost::system::error_code ec,
959 const dbusPropertiesList properties) {
960 if (ec)
961 {
962 return;
963 }
964 setProperties(properties);
965 },
966 setingsService, powerACBootObject, "org.freedesktop.DBus.Properties",
967 "GetAll", powerACBootIface);
968#endif
969}
970
971void PowerRestoreController::setProperties(const dbusPropertiesList& props)
972{
973 for (auto& [property, propValue] : props)
974 {
975 if (property == "PowerRestorePolicy")
976 {
977 const std::string* value = std::get_if<std::string>(&propValue);
978 if (value == nullptr)
979 {
980 lg2::error("Unable to read Power Restore Policy");
981 continue;
982 }
983 powerRestorePolicy = *value;
984 }
985 else if (property == "PowerRestoreDelay")
986 {
987 const uint64_t* value = std::get_if<uint64_t>(&propValue);
988 if (value == nullptr)
989 {
990 lg2::error("Unable to read Power Restore Delay");
991 continue;
992 }
993 powerRestoreDelay = *value / 1000000; // usec to sec
994 }
995#ifdef USE_ACBOOT
996 else if (property == "ACBoot")
997 {
998 const std::string* value = std::get_if<std::string>(&propValue);
999 if (value == nullptr)
1000 {
1001 lg2::error("Unable to read AC Boot status");
1002 continue;
1003 }
1004 acBoot = *value;
1005 }
1006#endif // USE_ACBOOT
1007 }
1008 invokeIfReady();
1009}
1010
1011void PowerRestoreController::invokeIfReady()
1012{
1013 if ((powerRestorePolicy.empty()) || (powerRestoreDelay < 0))
1014 {
1015 return;
1016 }
1017#ifdef USE_ACBOOT
1018 if (acBoot.empty() || acBoot == "Unknown")
1019 {
1020 return;
1021 }
1022#endif
1023
1024 matches.clear();
1025 if (!timerFired)
1026 {
1027 // Calculate the delay from now to meet the requested delay
1028 // Subtract the approximate uboot time
1029 static constexpr const int ubootSeconds = 20;
1030 int delay = powerRestoreDelay - ubootSeconds;
1031 // Subtract the time since boot
1032 struct sysinfo info = {};
1033 if (sysinfo(&info) == 0)
1034 {
1035 delay -= info.uptime;
1036 }
1037
1038 if (delay > 0)
1039 {
1040 powerRestoreTimer.expires_after(std::chrono::seconds(delay));
1041 lg2::info("Power Restore delay of {DELAY} seconds started", "DELAY",
1042 delay);
1043 powerRestoreTimer.async_wait([this](const boost::system::error_code
1044 ec) {
1045 if (ec)
1046 {
1047 // operation_aborted is expected if timer is canceled before
1048 // completion.
1049 if (ec == boost::asio::error::operation_aborted)
1050 {
1051 return;
1052 }
1053 lg2::error(
1054 "power restore policy async_wait failed: {ERROR_MSG}",
1055 "ERROR_MSG", ec.message());
1056 }
1057 else
1058 {
1059 lg2::info("Power Restore delay timer expired");
1060 }
1061 invoke();
1062 });
1063 timerFired = true;
1064 }
1065 else
1066 {
1067 invoke();
1068 }
1069 }
1070}
1071
1072void PowerRestoreController::invoke()
1073{
1074 // we want to run Power Restore only once
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001075 if (policyInvoked)
1076 {
1077 return;
1078 }
1079 policyInvoked = true;
1080
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001081 lg2::info("Invoking Power Restore Policy {POLICY}", "POLICY",
1082 powerRestorePolicy);
1083 if (powerRestorePolicy ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001084 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
1085 {
1086 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001087 setRestartCauseProperty(getRestartCause(RestartCause::powerPolicyOn));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001088 }
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001089 else if (powerRestorePolicy ==
Jason M. Bills418ce112021-09-08 15:15:05 -07001090 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore")
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001091 {
1092 if (wasPowerDropped())
1093 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001094 lg2::info("Power was dropped, restoring Host On state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001095 sendPowerControlEvent(Event::powerOnRequest);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001096 setRestartCauseProperty(
1097 getRestartCause(RestartCause::powerPolicyRestore));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001098 }
1099 else
1100 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001101 lg2::info("No power drop, restoring Host Off state");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001102 }
1103 }
Jason M. Bills94ce8eb2019-09-30 10:13:25 -07001104 // We're done with the previous power state for the restore policy, so store
1105 // the current state
1106 savePowerState(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001107}
1108
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001109bool PowerRestoreController::wasPowerDropped()
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001110{
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001111 std::string state = appState.get(PersistentState::Params::PowerState);
1112 return state == "xyz.openbmc_project.State.Chassis.PowerState.On";
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001113}
1114
Zev Weiss676ef2c2021-09-02 21:54:02 -05001115static void waitForGPIOEvent(const std::string& name,
1116 const std::function<void(bool)>& eventHandler,
1117 gpiod::line& line,
1118 boost::asio::posix::stream_descriptor& event)
1119{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001120 event.async_wait(boost::asio::posix::stream_descriptor::wait_read,
1121 [&name, eventHandler, &line,
1122 &event](const boost::system::error_code ec) {
1123 if (ec)
1124 {
1125 lg2::error(
1126 "{GPIO_NAME} fd handler error: {ERROR_MSG}",
1127 "GPIO_NAME", name, "ERROR_MSG", ec.message());
1128 // TODO: throw here to force power-control to
1129 // restart?
1130 return;
1131 }
1132 gpiod::line_event line_event = line.event_read();
1133 eventHandler(line_event.event_type ==
1134 gpiod::line_event::RISING_EDGE);
1135 waitForGPIOEvent(name, eventHandler, line, event);
1136 });
Zev Weiss676ef2c2021-09-02 21:54:02 -05001137}
1138
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001139static bool requestGPIOEvents(
Zev Weiss676ef2c2021-09-02 21:54:02 -05001140 const std::string& name, const std::function<void(bool)>& handler,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001141 gpiod::line& gpioLine,
1142 boost::asio::posix::stream_descriptor& gpioEventDescriptor)
1143{
1144 // Find the GPIO line
1145 gpioLine = gpiod::find_line(name);
1146 if (!gpioLine)
1147 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001148 lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001149 return false;
1150 }
1151
1152 try
1153 {
Andrei Kartashev3efcf372021-12-29 15:32:17 +03001154 gpioLine.request({appName, gpiod::line_request::EVENT_BOTH_EDGES, {}});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001155 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001156 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001157 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001158 lg2::error("Failed to request events for {GPIO_NAME}: {ERROR}",
1159 "GPIO_NAME", name, "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001160 return false;
1161 }
1162
1163 int gpioLineFd = gpioLine.event_get_fd();
1164 if (gpioLineFd < 0)
1165 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001166 lg2::error("Failed to get {GPIO_NAME} fd", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001167 return false;
1168 }
1169
1170 gpioEventDescriptor.assign(gpioLineFd);
1171
Zev Weiss676ef2c2021-09-02 21:54:02 -05001172 waitForGPIOEvent(name, handler, gpioLine, gpioEventDescriptor);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001173 return true;
1174}
1175
1176static bool setGPIOOutput(const std::string& name, const int value,
1177 gpiod::line& gpioLine)
1178{
1179 // Find the GPIO line
1180 gpioLine = gpiod::find_line(name);
1181 if (!gpioLine)
1182 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001183 lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001184 return false;
1185 }
1186
1187 // Request GPIO output to specified value
1188 try
1189 {
Andrei Kartashev3efcf372021-12-29 15:32:17 +03001190 gpioLine.request({appName, gpiod::line_request::DIRECTION_OUTPUT, {}},
1191 value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001192 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001193 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001194 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001195 lg2::error("Failed to request {GPIO_NAME} output: {ERROR}", "GPIO_NAME",
1196 name, "ERROR", e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001197 return false;
1198 }
1199
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001200 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1201 "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001202 return true;
1203}
1204
1205static int setMaskedGPIOOutputForMs(gpiod::line& maskedGPIOLine,
1206 const std::string& name, const int value,
1207 const int durationMs)
1208{
1209 // Set the masked GPIO line to the specified value
1210 maskedGPIOLine.set_value(value);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001211 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
1212 "GPIO_VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001213 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001214 gpioAssertTimer.async_wait(
1215 [maskedGPIOLine, value, name](const boost::system::error_code ec) {
1216 // Set the masked GPIO line back to the opposite value
1217 maskedGPIOLine.set_value(!value);
1218 lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
1219 if (ec)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001220 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001221 // operation_aborted is expected if timer is canceled before
1222 // completion.
1223 if (ec != boost::asio::error::operation_aborted)
1224 {
1225 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1226 "GPIO_NAME", name, "ERROR_MSG", ec.message());
1227 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001228 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001229 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001230 return 0;
1231}
1232
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001233static int setGPIOOutputForMs(const ConfigData& config, const int value,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001234 const int durationMs)
1235{
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001236 // If the requested GPIO is masked, use the mask line to set the output
1237 if (powerButtonMask && config.lineName == powerOutConfig.lineName)
1238 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001239 return setMaskedGPIOOutputForMs(powerButtonMask, config.lineName, value,
1240 durationMs);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001241 }
1242 if (resetButtonMask && config.lineName == resetOutConfig.lineName)
1243 {
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001244 return setMaskedGPIOOutputForMs(resetButtonMask, config.lineName, value,
1245 durationMs);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001246 }
1247
1248 // No mask set, so request and set the GPIO normally
1249 gpiod::line gpioLine;
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001250 if (!setGPIOOutput(config.lineName, value, gpioLine))
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001251 {
1252 return -1;
1253 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07001254 const std::string name = config.lineName;
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04001255
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001256 gpioAssertTimer.expires_after(std::chrono::milliseconds(durationMs));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001257 gpioAssertTimer.async_wait(
1258 [gpioLine, value, name](const boost::system::error_code ec) {
1259 // Set the GPIO line back to the opposite value
1260 gpioLine.set_value(!value);
1261 lg2::info("{GPIO_NAME} released", "GPIO_NAME", name);
1262 if (ec)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001263 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001264 // operation_aborted is expected if timer is canceled before
1265 // completion.
1266 if (ec != boost::asio::error::operation_aborted)
1267 {
1268 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
1269 "GPIO_NAME", name, "ERROR_MSG", ec.message());
1270 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001271 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001272 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001273 return 0;
1274}
1275
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001276static int assertGPIOForMs(const ConfigData& config, const int durationMs)
1277{
1278 return setGPIOOutputForMs(config, config.polarity, durationMs);
1279}
1280
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001281static void powerOn()
1282{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001283 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001284}
Naveen Moses117c34e2021-05-26 20:10:51 +05301285#ifdef CHASSIS_SYSTEM_RESET
1286static int slotPowerOn()
1287{
1288 if (power_control::slotPowerState != power_control::SlotPowerState::on)
1289 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001290
Naveen Moses117c34e2021-05-26 20:10:51 +05301291 slotPowerLine.set_value(1);
1292
1293 if (slotPowerLine.get_value() > 0)
1294 {
1295 setSlotPowerState(SlotPowerState::on);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001296 lg2::info("Slot Power is switched On\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301297 }
1298 else
1299 {
1300 return -1;
1301 }
1302 }
1303 else
1304 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001305 lg2::info("Slot Power is already in 'On' state\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301306 return -1;
1307 }
1308 return 0;
1309}
1310static int slotPowerOff()
1311{
1312 if (power_control::slotPowerState != power_control::SlotPowerState::off)
1313 {
1314 slotPowerLine.set_value(0);
1315
1316 if (!(slotPowerLine.get_value() > 0))
1317 {
1318 setSlotPowerState(SlotPowerState::off);
1319 setPowerState(PowerState::off);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001320 lg2::info("Slot Power is switched Off\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301321 }
1322 else
1323 {
1324 return -1;
1325 }
1326 }
1327 else
1328 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001329 lg2::info("Slot Power is already in 'Off' state\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301330 return -1;
1331 }
1332 return 0;
1333}
1334static void slotPowerCycle()
1335{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001336 lg2::info("Slot Power Cycle started\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301337 slotPowerOff();
1338 slotPowerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001339 std::chrono::milliseconds(TimerMap["SlotPowerCycleMs"]));
Naveen Moses117c34e2021-05-26 20:10:51 +05301340 slotPowerCycleTimer.async_wait([](const boost::system::error_code ec) {
1341 if (ec)
1342 {
1343 if (ec != boost::asio::error::operation_aborted)
1344 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001345 lg2::error(
1346 "Slot Power cycle timer async_wait failed: {ERROR_MSG}",
1347 "ERROR_MSG", ec.message());
Naveen Moses117c34e2021-05-26 20:10:51 +05301348 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001349 lg2::info("Slot Power cycle timer canceled\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301350 return;
1351 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001352 lg2::info("Slot Power cycle timer completed\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301353 slotPowerOn();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001354 lg2::info("Slot Power Cycle Completed\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05301355 });
1356}
1357#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001358static void gracefulPowerOff()
1359{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001360 assertGPIOForMs(powerOutConfig, TimerMap["PowerPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001361}
1362
1363static void forcePowerOff()
1364{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001365 if (assertGPIOForMs(powerOutConfig, TimerMap["ForceOffPulseMs"]) < 0)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001366 {
1367 return;
1368 }
1369
Jason M. Billsc6961b62021-10-21 14:08:02 -07001370 // If the force off timer expires, then the power-button override failed
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001371 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
1372 if (ec)
1373 {
1374 // operation_aborted is expected if timer is canceled before
1375 // completion.
1376 if (ec != boost::asio::error::operation_aborted)
1377 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001378 lg2::error("Force power off async_wait failed: {ERROR_MSG}",
1379 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001380 }
1381 return;
1382 }
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001383
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001384 lg2::error("Power-button override failed. Not sure what to do now.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001385 });
1386}
1387
1388static void reset()
1389{
Jason M. Billsc8c90c82021-09-22 14:34:04 -07001390 assertGPIOForMs(resetOutConfig, TimerMap["ResetPulseMs"]);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001391}
1392
1393static void gracefulPowerOffTimerStart()
1394{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001395 lg2::info("Graceful power-off timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001396 gracefulPowerOffTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001397 std::chrono::seconds(TimerMap["GracefulPowerOffS"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001398 gracefulPowerOffTimer.async_wait([](const boost::system::error_code ec) {
1399 if (ec)
1400 {
1401 // operation_aborted is expected if timer is canceled before
1402 // completion.
1403 if (ec != boost::asio::error::operation_aborted)
1404 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001405 lg2::error("Graceful power-off async_wait failed: {ERROR_MSG}",
1406 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001407 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001408 lg2::info("Graceful power-off timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001409 return;
1410 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001411 lg2::info("Graceful power-off timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001412 sendPowerControlEvent(Event::gracefulPowerOffTimerExpired);
1413 });
1414}
1415
1416static void powerCycleTimerStart()
1417{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001418 lg2::info("Power-cycle timer started");
Priyatharshan P70120512020-09-16 18:47:20 +05301419 powerCycleTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001420 std::chrono::milliseconds(TimerMap["PowerCycleMs"]));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001421 powerCycleTimer.async_wait([](const boost::system::error_code ec) {
1422 if (ec)
1423 {
1424 // operation_aborted is expected if timer is canceled before
1425 // completion.
1426 if (ec != boost::asio::error::operation_aborted)
1427 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001428 lg2::error("Power-cycle async_wait failed: {ERROR_MSG}",
1429 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001430 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001431 lg2::info("Power-cycle timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001432 return;
1433 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001434 lg2::info("Power-cycle timer completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001435 sendPowerControlEvent(Event::powerCycleTimerExpired);
1436 });
1437}
1438
1439static void psPowerOKWatchdogTimerStart()
1440{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001441 lg2::info("power supply power OK watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001442 psPowerOKWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001443 std::chrono::milliseconds(TimerMap["PsPowerOKWatchdogMs"]));
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001444 psPowerOKWatchdogTimer.async_wait([](const boost::system::error_code ec) {
1445 if (ec)
1446 {
1447 // operation_aborted is expected if timer is canceled before
1448 // completion.
1449 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001450 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001451 lg2::error(
1452 "power supply power OK watchdog async_wait failed: {ERROR_MSG}",
1453 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001454 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001455 lg2::info("power supply power OK watchdog timer canceled");
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001456 return;
1457 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001458 lg2::info("power supply power OK watchdog timer expired");
Jason M. Bills41a49aa2021-03-03 16:03:25 -08001459 sendPowerControlEvent(Event::psPowerOKWatchdogTimerExpired);
1460 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001461}
1462
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001463static void warmResetCheckTimerStart()
1464{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001465 lg2::info("Warm reset check timer started");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001466 warmResetCheckTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001467 std::chrono::milliseconds(TimerMap["WarmResetCheckMs"]));
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001468 warmResetCheckTimer.async_wait([](const boost::system::error_code ec) {
1469 if (ec)
1470 {
1471 // operation_aborted is expected if timer is canceled before
1472 // completion.
1473 if (ec != boost::asio::error::operation_aborted)
1474 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001475 lg2::error("Warm reset check async_wait failed: {ERROR_MSG}",
1476 "ERROR_MSG", ec.message());
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001477 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001478 lg2::info("Warm reset check timer canceled");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001479 return;
1480 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001481 lg2::info("Warm reset check timer completed");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001482 sendPowerControlEvent(Event::warmResetDetected);
1483 });
1484}
1485
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001486static void pohCounterTimerStart()
1487{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001488 lg2::info("POH timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001489 // Set the time-out as 1 hour, to align with POH command in ipmid
1490 pohCounterTimer.expires_after(std::chrono::hours(1));
1491 pohCounterTimer.async_wait([](const boost::system::error_code& ec) {
1492 if (ec)
1493 {
1494 // operation_aborted is expected if timer is canceled before
1495 // completion.
1496 if (ec != boost::asio::error::operation_aborted)
1497 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001498 lg2::error("POH timer async_wait failed: {ERROR_MSG}",
1499 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001500 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001501 lg2::info("POH timer canceled");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001502 return;
1503 }
1504
1505 if (getHostState(powerState) !=
1506 "xyz.openbmc_project.State.Host.HostState.Running")
1507 {
1508 return;
1509 }
1510
1511 conn->async_method_call(
1512 [](boost::system::error_code ec,
1513 const std::variant<uint32_t>& pohCounterProperty) {
1514 if (ec)
1515 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001516 lg2::error("error getting poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001517 return;
1518 }
1519 const uint32_t* pohCounter =
1520 std::get_if<uint32_t>(&pohCounterProperty);
1521 if (pohCounter == nullptr)
1522 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001523 lg2::error("unable to read poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001524 return;
1525 }
1526
1527 conn->async_method_call(
1528 [](boost::system::error_code ec) {
1529 if (ec)
1530 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001531 lg2::error("failed to set poh counter");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001532 }
1533 },
1534 "xyz.openbmc_project.Settings",
1535 "/xyz/openbmc_project/state/chassis0",
1536 "org.freedesktop.DBus.Properties", "Set",
1537 "xyz.openbmc_project.State.PowerOnHours", "POHCounter",
1538 std::variant<uint32_t>(*pohCounter + 1));
1539 },
1540 "xyz.openbmc_project.Settings",
1541 "/xyz/openbmc_project/state/chassis0",
1542 "org.freedesktop.DBus.Properties", "Get",
1543 "xyz.openbmc_project.State.PowerOnHours", "POHCounter");
1544
1545 pohCounterTimerStart();
1546 });
1547}
1548
1549static void currentHostStateMonitor()
1550{
Yong Li8d660212019-12-27 10:18:10 +08001551 if (getHostState(powerState) ==
1552 "xyz.openbmc_project.State.Host.HostState.Running")
1553 {
1554 pohCounterTimerStart();
1555 // Clear the restart cause set for the next restart
1556 clearRestartCause();
1557 }
1558 else
1559 {
1560 pohCounterTimer.cancel();
1561 // Set the restart cause set for this restart
1562 setRestartCause();
1563 }
1564
Patrick Williams439b9c32022-07-22 19:26:53 -05001565 static auto match = sdbusplus::bus::match_t(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001566 *conn,
1567 "type='signal',member='PropertiesChanged', "
1568 "interface='org.freedesktop.DBus.Properties', "
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001569 "arg0='xyz.openbmc_project.State.Host'",
Patrick Williams439b9c32022-07-22 19:26:53 -05001570 [](sdbusplus::message_t& message) {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001571 std::string intfName;
1572 std::map<std::string, std::variant<std::string>> properties;
1573
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001574 try
1575 {
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001576 message.read(intfName, properties);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001577 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05001578 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001579 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001580 lg2::error("Unable to read host state: {ERROR}", "ERROR", e);
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001581 return;
1582 }
1583 if (properties.empty())
1584 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001585 lg2::error("ERROR: Empty PropertiesChanged signal received");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001586 return;
1587 }
1588
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001589 // We only want to check for CurrentHostState
1590 if (properties.begin()->first != "CurrentHostState")
1591 {
1592 return;
1593 }
1594 std::string* currentHostState =
1595 std::get_if<std::string>(&(properties.begin()->second));
1596 if (currentHostState == nullptr)
1597 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001598 lg2::error("{PROPERTY} property invalid", "PROPERTY",
1599 properties.begin()->first);
Jason M. Bills6a6485a2020-07-24 14:07:07 -07001600 return;
1601 }
1602
1603 if (*currentHostState ==
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001604 "xyz.openbmc_project.State.Host.HostState.Running")
1605 {
1606 pohCounterTimerStart();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001607 // Clear the restart cause set for the next restart
1608 clearRestartCause();
Yong Li8d660212019-12-27 10:18:10 +08001609 sd_journal_send("MESSAGE=Host system DC power is on",
1610 "PRIORITY=%i", LOG_INFO,
1611 "REDFISH_MESSAGE_ID=%s",
1612 "OpenBMC.0.1.DCPowerOn", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001613 }
1614 else
1615 {
1616 pohCounterTimer.cancel();
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301617 // POST_COMPLETE GPIO event is not working in some platforms
1618 // when power state is changed to OFF. This resulted in
1619 // 'OperatingSystemState' to stay at 'Standby', even though
1620 // system is OFF. Set 'OperatingSystemState' to 'Inactive'
1621 // if HostState is trurned to OFF.
Tim Lee86239182021-12-23 11:46:01 +08001622 setOperatingSystemState(OperatingSystemStateStage::Inactive);
AppaRao Puli8f5cb6a2020-01-14 02:47:29 +05301623
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001624 // Set the restart cause set for this restart
1625 setRestartCause();
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001626#ifdef USE_ACBOOT
Rashmi RV89f61312020-01-22 15:41:50 +05301627 resetACBootProperty();
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03001628#endif // USE_ACBOOT
Yong Li8d660212019-12-27 10:18:10 +08001629 sd_journal_send("MESSAGE=Host system DC power is off",
1630 "PRIORITY=%i", LOG_INFO,
1631 "REDFISH_MESSAGE_ID=%s",
1632 "OpenBMC.0.1.DCPowerOff", NULL);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001633 }
1634 });
1635}
1636
1637static void sioPowerGoodWatchdogTimerStart()
1638{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001639 lg2::info("SIO power good watchdog timer started");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001640 sioPowerGoodWatchdogTimer.expires_after(
Jason M. Billsaeefe042021-09-08 14:56:11 -07001641 std::chrono::milliseconds(TimerMap["SioPowerGoodWatchdogMs"]));
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001642 sioPowerGoodWatchdogTimer.async_wait([](const boost::system::error_code
1643 ec) {
1644 if (ec)
1645 {
1646 // operation_aborted is expected if timer is canceled before
1647 // completion.
1648 if (ec != boost::asio::error::operation_aborted)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001649 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001650 lg2::error(
1651 "SIO power good watchdog async_wait failed: {ERROR_MSG}",
1652 "ERROR_MSG", ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001653 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001654 lg2::info("SIO power good watchdog timer canceled");
1655 return;
1656 }
1657 lg2::info("SIO power good watchdog timer completed");
1658 sendPowerControlEvent(Event::sioPowerGoodWatchdogTimerExpired);
1659 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001660}
1661
1662static void powerStateOn(const Event event)
1663{
1664 logEvent(__FUNCTION__, event);
1665 switch (event)
1666 {
1667 case Event::psPowerOKDeAssert:
1668 setPowerState(PowerState::off);
1669 // DC power is unexpectedly lost, beep
1670 beep(beepPowerFail);
1671 break;
1672 case Event::sioS5Assert:
1673 setPowerState(PowerState::transitionToOff);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001674 addRestartCause(RestartCause::softReset);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001675 break;
Jason M. Billsfb957332021-01-28 13:18:46 -08001676#if USE_PLT_RST
1677 case Event::pltRstAssert:
1678#else
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001679 case Event::postCompleteDeAssert:
Jason M. Billsfb957332021-01-28 13:18:46 -08001680#endif
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001681 setPowerState(PowerState::checkForWarmReset);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07001682 addRestartCause(RestartCause::softReset);
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001683 warmResetCheckTimerStart();
1684 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001685 case Event::powerButtonPressed:
1686 setPowerState(PowerState::gracefulTransitionToOff);
1687 gracefulPowerOffTimerStart();
1688 break;
1689 case Event::powerOffRequest:
1690 setPowerState(PowerState::transitionToOff);
1691 forcePowerOff();
1692 break;
1693 case Event::gracefulPowerOffRequest:
1694 setPowerState(PowerState::gracefulTransitionToOff);
1695 gracefulPowerOffTimerStart();
1696 gracefulPowerOff();
1697 break;
1698 case Event::powerCycleRequest:
1699 setPowerState(PowerState::transitionToCycleOff);
1700 forcePowerOff();
1701 break;
1702 case Event::gracefulPowerCycleRequest:
1703 setPowerState(PowerState::gracefulTransitionToCycleOff);
1704 gracefulPowerOffTimerStart();
1705 gracefulPowerOff();
1706 break;
1707 case Event::resetRequest:
1708 reset();
1709 break;
1710 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001711 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001712 break;
1713 }
1714}
1715
1716static void powerStateWaitForPSPowerOK(const Event event)
1717{
1718 logEvent(__FUNCTION__, event);
1719 switch (event)
1720 {
1721 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301722 {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001723 // Cancel any GPIO assertions held during the transition
1724 gpioAssertTimer.cancel();
1725 psPowerOKWatchdogTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301726 if (sioEnabled == true)
1727 {
1728 sioPowerGoodWatchdogTimerStart();
1729 setPowerState(PowerState::waitForSIOPowerGood);
1730 }
1731 else
1732 {
1733 setPowerState(PowerState::on);
1734 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001735 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301736 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001737 case Event::psPowerOKWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001738 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001739 psPowerOKFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001740 break;
Vijay Khemka0eef6b62019-10-22 12:22:52 -07001741 case Event::sioPowerGoodAssert:
1742 psPowerOKWatchdogTimer.cancel();
1743 setPowerState(PowerState::on);
1744 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001745 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001746 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001747 break;
1748 }
1749}
1750
1751static void powerStateWaitForSIOPowerGood(const Event event)
1752{
1753 logEvent(__FUNCTION__, event);
1754 switch (event)
1755 {
1756 case Event::sioPowerGoodAssert:
1757 sioPowerGoodWatchdogTimer.cancel();
1758 setPowerState(PowerState::on);
1759 break;
1760 case Event::sioPowerGoodWatchdogTimerExpired:
Jason M. Bills273d7892020-06-17 14:46:57 -07001761 setPowerState(PowerState::off);
Jason M. Bills6c2ad362019-08-01 16:53:35 -07001762 systemPowerGoodFailedLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001763 break;
1764 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001765 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001766 break;
1767 }
1768}
1769
1770static void powerStateOff(const Event event)
1771{
1772 logEvent(__FUNCTION__, event);
1773 switch (event)
1774 {
1775 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301776 {
1777 if (sioEnabled == true)
1778 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001779 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301780 setPowerState(PowerState::waitForSIOPowerGood);
1781 }
1782 else
1783 {
1784 setPowerState(PowerState::on);
1785 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001786 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301787 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001788 case Event::sioS5DeAssert:
Jason M. Billsfe159032022-09-01 16:03:37 -07001789 psPowerOKWatchdogTimerStart();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001790 setPowerState(PowerState::waitForPSPowerOK);
1791 break;
Jason M. Bills273d7892020-06-17 14:46:57 -07001792 case Event::sioPowerGoodAssert:
1793 setPowerState(PowerState::on);
1794 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001795 case Event::powerButtonPressed:
1796 psPowerOKWatchdogTimerStart();
1797 setPowerState(PowerState::waitForPSPowerOK);
1798 break;
1799 case Event::powerOnRequest:
1800 psPowerOKWatchdogTimerStart();
1801 setPowerState(PowerState::waitForPSPowerOK);
1802 powerOn();
1803 break;
1804 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001805 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001806 break;
1807 }
1808}
1809
1810static void powerStateTransitionToOff(const Event event)
1811{
1812 logEvent(__FUNCTION__, event);
1813 switch (event)
1814 {
1815 case Event::psPowerOKDeAssert:
1816 // Cancel any GPIO assertions held during the transition
1817 gpioAssertTimer.cancel();
1818 setPowerState(PowerState::off);
1819 break;
1820 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001821 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001822 break;
1823 }
1824}
1825
1826static void powerStateGracefulTransitionToOff(const Event event)
1827{
1828 logEvent(__FUNCTION__, event);
1829 switch (event)
1830 {
1831 case Event::psPowerOKDeAssert:
1832 gracefulPowerOffTimer.cancel();
1833 setPowerState(PowerState::off);
1834 break;
1835 case Event::gracefulPowerOffTimerExpired:
1836 setPowerState(PowerState::on);
1837 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001838 case Event::powerOffRequest:
1839 gracefulPowerOffTimer.cancel();
1840 setPowerState(PowerState::transitionToOff);
1841 forcePowerOff();
1842 break;
1843 case Event::powerCycleRequest:
1844 gracefulPowerOffTimer.cancel();
1845 setPowerState(PowerState::transitionToCycleOff);
1846 forcePowerOff();
1847 break;
1848 case Event::resetRequest:
1849 gracefulPowerOffTimer.cancel();
1850 setPowerState(PowerState::on);
1851 reset();
1852 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001853 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001854 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001855 break;
1856 }
1857}
1858
1859static void powerStateCycleOff(const Event event)
1860{
1861 logEvent(__FUNCTION__, event);
1862 switch (event)
1863 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001864 case Event::psPowerOKAssert:
Priyatharshan P19c47a32020-08-12 18:16:43 +05301865 {
Jason M. Bills35aa6652020-04-30 16:24:55 -07001866 powerCycleTimer.cancel();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301867 if (sioEnabled == true)
1868 {
Jason M. Bills7e27d3d2021-09-08 14:51:09 -07001869 sioPowerGoodWatchdogTimerStart();
Priyatharshan P19c47a32020-08-12 18:16:43 +05301870 setPowerState(PowerState::waitForSIOPowerGood);
1871 }
1872 else
1873 {
1874 setPowerState(PowerState::on);
1875 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001876 break;
Priyatharshan P19c47a32020-08-12 18:16:43 +05301877 }
Jason M. Bills35aa6652020-04-30 16:24:55 -07001878 case Event::sioS5DeAssert:
1879 powerCycleTimer.cancel();
Jason M. Billsfe159032022-09-01 16:03:37 -07001880 psPowerOKWatchdogTimerStart();
Jason M. Bills35aa6652020-04-30 16:24:55 -07001881 setPowerState(PowerState::waitForPSPowerOK);
1882 break;
1883 case Event::powerButtonPressed:
1884 powerCycleTimer.cancel();
1885 psPowerOKWatchdogTimerStart();
1886 setPowerState(PowerState::waitForPSPowerOK);
1887 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001888 case Event::powerCycleTimerExpired:
1889 psPowerOKWatchdogTimerStart();
1890 setPowerState(PowerState::waitForPSPowerOK);
1891 powerOn();
1892 break;
1893 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001894 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001895 break;
1896 }
1897}
1898
1899static void powerStateTransitionToCycleOff(const Event event)
1900{
1901 logEvent(__FUNCTION__, event);
1902 switch (event)
1903 {
1904 case Event::psPowerOKDeAssert:
1905 // Cancel any GPIO assertions held during the transition
1906 gpioAssertTimer.cancel();
1907 setPowerState(PowerState::cycleOff);
1908 powerCycleTimerStart();
1909 break;
1910 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001911 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001912 break;
1913 }
1914}
1915
1916static void powerStateGracefulTransitionToCycleOff(const Event event)
1917{
1918 logEvent(__FUNCTION__, event);
1919 switch (event)
1920 {
1921 case Event::psPowerOKDeAssert:
1922 gracefulPowerOffTimer.cancel();
1923 setPowerState(PowerState::cycleOff);
1924 powerCycleTimerStart();
1925 break;
1926 case Event::gracefulPowerOffTimerExpired:
1927 setPowerState(PowerState::on);
1928 break;
Jason M. Bills22e0bec2021-03-04 12:54:04 -08001929 case Event::powerOffRequest:
1930 gracefulPowerOffTimer.cancel();
1931 setPowerState(PowerState::transitionToOff);
1932 forcePowerOff();
1933 break;
1934 case Event::powerCycleRequest:
1935 gracefulPowerOffTimer.cancel();
1936 setPowerState(PowerState::transitionToCycleOff);
1937 forcePowerOff();
1938 break;
1939 case Event::resetRequest:
1940 gracefulPowerOffTimer.cancel();
1941 setPowerState(PowerState::on);
1942 reset();
1943 break;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001944 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001945 lg2::info("No action taken.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07001946 break;
1947 }
1948}
1949
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001950static void powerStateCheckForWarmReset(const Event event)
1951{
1952 logEvent(__FUNCTION__, event);
1953 switch (event)
1954 {
1955 case Event::sioS5Assert:
1956 warmResetCheckTimer.cancel();
1957 setPowerState(PowerState::transitionToOff);
1958 break;
1959 case Event::warmResetDetected:
1960 setPowerState(PowerState::on);
1961 break;
P.K. Lee344dae82019-11-27 16:35:05 +08001962 case Event::psPowerOKDeAssert:
1963 warmResetCheckTimer.cancel();
1964 setPowerState(PowerState::off);
1965 // DC power is unexpectedly lost, beep
1966 beep(beepPowerFail);
1967 break;
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001968 default:
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001969 lg2::info("No action taken.");
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07001970 break;
1971 }
1972}
1973
Zev Weiss584aa132021-09-02 19:21:52 -05001974static void psPowerOKHandler(bool state)
1975{
1976 Event powerControlEvent =
1977 state ? Event::psPowerOKAssert : Event::psPowerOKDeAssert;
1978 sendPowerControlEvent(powerControlEvent);
1979}
1980
Zev Weiss584aa132021-09-02 19:21:52 -05001981static void sioPowerGoodHandler(bool state)
1982{
1983 Event powerControlEvent =
1984 state ? Event::sioPowerGoodAssert : Event::sioPowerGoodDeAssert;
1985 sendPowerControlEvent(powerControlEvent);
1986}
1987
Zev Weiss584aa132021-09-02 19:21:52 -05001988static void sioOnControlHandler(bool state)
1989{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08001990 lg2::info("SIO_ONCONTROL value changed: {VALUE}", "VALUE",
1991 static_cast<int>(state));
Zev Weiss584aa132021-09-02 19:21:52 -05001992}
1993
Zev Weiss584aa132021-09-02 19:21:52 -05001994static void sioS5Handler(bool state)
1995{
1996 Event powerControlEvent = state ? Event::sioS5DeAssert : Event::sioS5Assert;
1997 sendPowerControlEvent(powerControlEvent);
1998}
1999
Zev Weiss584aa132021-09-02 19:21:52 -05002000static void powerButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002001{
Zev Weiss584aa132021-09-02 19:21:52 -05002002 powerButtonIface->set_property("ButtonPressed", !state);
2003 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002004 {
2005 powerButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002006 if (!powerButtonMask)
2007 {
2008 sendPowerControlEvent(Event::powerButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002009 addRestartCause(RestartCause::powerButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002010 }
2011 else
2012 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002013 lg2::info("power button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002014 }
2015 }
Zev Weiss584aa132021-09-02 19:21:52 -05002016}
2017
Zev Weiss584aa132021-09-02 19:21:52 -05002018static void resetButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002019{
Zev Weiss584aa132021-09-02 19:21:52 -05002020 resetButtonIface->set_property("ButtonPressed", !state);
2021 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002022 {
2023 resetButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002024 if (!resetButtonMask)
2025 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002026 sendPowerControlEvent(Event::resetButtonPressed);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07002027 addRestartCause(RestartCause::resetButton);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002028 }
2029 else
2030 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002031 lg2::info("reset button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002032 }
2033 }
Zev Weiss584aa132021-09-02 19:21:52 -05002034}
2035
Vijay Khemka04175c22020-10-09 14:28:11 -07002036#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002037static constexpr auto systemdBusname = "org.freedesktop.systemd1";
2038static constexpr auto systemdPath = "/org/freedesktop/systemd1";
2039static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
2040static constexpr auto systemTargetName = "chassis-system-reset.target";
2041
2042void systemReset()
2043{
2044 conn->async_method_call(
2045 [](boost::system::error_code ec) {
2046 if (ec)
2047 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002048 lg2::error("Failed to call chassis system reset: {ERR}", "ERR",
2049 ec.message());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002050 }
2051 },
2052 systemdBusname, systemdPath, systemdInterface, "StartUnit",
2053 systemTargetName, "replace");
2054}
Vijay Khemka04175c22020-10-09 14:28:11 -07002055#endif
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002056
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002057static void nmiSetEnableProperty(bool value)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002058{
2059 conn->async_method_call(
2060 [](boost::system::error_code ec) {
2061 if (ec)
2062 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002063 lg2::error("failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002064 }
2065 },
Chen Yugang303bd582019-11-01 08:45:06 +08002066 "xyz.openbmc_project.Settings",
2067 "/xyz/openbmc_project/Chassis/Control/NMISource",
2068 "org.freedesktop.DBus.Properties", "Set",
2069 "xyz.openbmc_project.Chassis.Control.NMISource", "Enabled",
2070 std::variant<bool>{value});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002071}
2072
2073static void nmiReset(void)
2074{
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002075 const static constexpr int nmiOutPulseTimeMs = 200;
2076
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002077 lg2::info("NMI out action");
Jian Zhang461a1662022-09-22 11:29:01 +08002078 nmiOutLine.set_value(nmiOutConfig.polarity);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002079 lg2::info("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME",
Jian Zhang461a1662022-09-22 11:29:01 +08002080 nmiOutConfig.lineName, "GPIO_VALUE", nmiOutConfig.polarity);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002081 gpioAssertTimer.expires_after(std::chrono::milliseconds(nmiOutPulseTimeMs));
2082 gpioAssertTimer.async_wait([](const boost::system::error_code ec) {
2083 // restore the NMI_OUT GPIO line back to the opposite value
Jian Zhang461a1662022-09-22 11:29:01 +08002084 nmiOutLine.set_value(!nmiOutConfig.polarity);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002085 lg2::info("{GPIO_NAME} released", "GPIO_NAME", nmiOutConfig.lineName);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002086 if (ec)
2087 {
2088 // operation_aborted is expected if timer is canceled before
2089 // completion.
2090 if (ec != boost::asio::error::operation_aborted)
2091 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002092 lg2::error("{GPIO_NAME} async_wait failed: {ERROR_MSG}",
2093 "GPIO_NAME", nmiOutConfig.lineName, "ERROR_MSG",
2094 ec.message());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002095 }
2096 }
2097 });
2098 // log to redfish
2099 nmiDiagIntLog();
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002100 lg2::info("NMI out action completed");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002101 // reset Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002102 nmiSetEnableProperty(false);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002103}
2104
2105static void nmiSourcePropertyMonitor(void)
2106{
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002107 lg2::info("NMI Source Property Monitor");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002108
Patrick Williams439b9c32022-07-22 19:26:53 -05002109 static std::unique_ptr<sdbusplus::bus::match_t> nmiSourceMatch =
2110 std::make_unique<sdbusplus::bus::match_t>(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002111 *conn,
2112 "type='signal',interface='org.freedesktop.DBus.Properties',"
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002113 "member='PropertiesChanged',"
2114 "arg0namespace='xyz.openbmc_project.Chassis.Control.NMISource'",
Patrick Williams439b9c32022-07-22 19:26:53 -05002115 [](sdbusplus::message_t& msg) {
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002116 std::string interfaceName;
2117 boost::container::flat_map<std::string,
2118 std::variant<bool, std::string>>
2119 propertiesChanged;
2120 std::string state;
2121 bool value = true;
2122 try
2123 {
2124 msg.read(interfaceName, propertiesChanged);
2125 if (propertiesChanged.begin()->first == "Enabled")
2126 {
2127 value =
2128 std::get<bool>(propertiesChanged.begin()->second);
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002129 lg2::info(
2130 "NMI Enabled propertiesChanged value: {VALUE}",
2131 "VALUE", value);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002132 nmiEnabled = value;
2133 if (nmiEnabled)
2134 {
2135 nmiReset();
2136 }
2137 }
2138 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002139 catch (const std::exception& e)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002140 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002141 lg2::error("Unable to read NMI source: {ERROR}", "ERROR",
2142 e);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002143 return;
2144 }
2145 });
2146}
2147
2148static void setNmiSource()
2149{
2150 conn->async_method_call(
2151 [](boost::system::error_code ec) {
2152 if (ec)
2153 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002154 lg2::error("failed to set NMI source");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002155 }
2156 },
Chen Yugang303bd582019-11-01 08:45:06 +08002157 "xyz.openbmc_project.Settings",
2158 "/xyz/openbmc_project/Chassis/Control/NMISource",
2159 "org.freedesktop.DBus.Properties", "Set",
2160 "xyz.openbmc_project.Chassis.Control.NMISource", "BMCSource",
Jason M. Bills418ce112021-09-08 15:15:05 -07002161 std::variant<std::string>{
2162 "xyz.openbmc_project.Chassis.Control.NMISource.BMCSourceSignal.FpBtn"});
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002163 // set Enable Property
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002164 nmiSetEnableProperty(true);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002165}
2166
Zev Weiss584aa132021-09-02 19:21:52 -05002167static void nmiButtonHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002168{
Zev Weiss584aa132021-09-02 19:21:52 -05002169 nmiButtonIface->set_property("ButtonPressed", !state);
2170 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002171 {
2172 nmiButtonPressLog();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002173 if (nmiButtonMasked)
2174 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002175 lg2::info("NMI button press masked");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002176 }
2177 else
2178 {
2179 setNmiSource();
2180 }
2181 }
Zev Weiss584aa132021-09-02 19:21:52 -05002182}
2183
Zev Weiss584aa132021-09-02 19:21:52 -05002184static void idButtonHandler(bool state)
2185{
2186 idButtonIface->set_property("ButtonPressed", !state);
2187}
2188
Jason M. Billsfb957332021-01-28 13:18:46 -08002189static void pltRstHandler(bool pltRst)
2190{
2191 if (pltRst)
2192 {
2193 sendPowerControlEvent(Event::pltRstDeAssert);
2194 }
2195 else
2196 {
2197 sendPowerControlEvent(Event::pltRstAssert);
2198 }
2199}
2200
Patrick Williams439b9c32022-07-22 19:26:53 -05002201[[maybe_unused]] static void hostMiscHandler(sdbusplus::message_t& msg)
Jason M. Billsfb957332021-01-28 13:18:46 -08002202{
2203 std::string interfaceName;
2204 boost::container::flat_map<std::string, std::variant<bool>>
2205 propertiesChanged;
Jason M. Billsfb957332021-01-28 13:18:46 -08002206 try
2207 {
2208 msg.read(interfaceName, propertiesChanged);
2209 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002210 catch (const std::exception& e)
Jason M. Billsfb957332021-01-28 13:18:46 -08002211 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002212 lg2::error("Unable to read Host Misc status: {ERROR}", "ERROR", e);
Jason M. Billsfb957332021-01-28 13:18:46 -08002213 return;
2214 }
2215 if (propertiesChanged.empty())
2216 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002217 lg2::error("ERROR: Empty Host.Misc PropertiesChanged signal received");
Jason M. Billsfb957332021-01-28 13:18:46 -08002218 return;
2219 }
2220
2221 for (auto& [property, value] : propertiesChanged)
2222 {
2223 if (property == "ESpiPlatformReset")
2224 {
2225 bool* pltRst = std::get_if<bool>(&value);
2226 if (pltRst == nullptr)
2227 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002228 lg2::error("{PROPERTY} property invalid", "PROPERTY", property);
Jason M. Billsfb957332021-01-28 13:18:46 -08002229 return;
2230 }
2231 pltRstHandler(*pltRst);
2232 }
2233 }
2234}
2235
Zev Weiss584aa132021-09-02 19:21:52 -05002236static void postCompleteHandler(bool state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002237{
Zev Weiss584aa132021-09-02 19:21:52 -05002238 if (!state)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002239 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002240 sendPowerControlEvent(Event::postCompleteAssert);
Tim Lee86239182021-12-23 11:46:01 +08002241 setOperatingSystemState(OperatingSystemStateStage::Standby);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002242 }
2243 else
2244 {
Jason M. Billse9a9e2d2019-08-08 14:01:19 -07002245 sendPowerControlEvent(Event::postCompleteDeAssert);
Tim Lee86239182021-12-23 11:46:01 +08002246 setOperatingSystemState(OperatingSystemStateStage::Inactive);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002247 }
Zev Weiss584aa132021-09-02 19:21:52 -05002248}
2249
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302250static int loadConfigValues()
2251{
2252 const std::string configFilePath =
2253 "/usr/share/x86-power-control/power-config-host" + power_control::node +
2254 ".json";
2255 std::ifstream configFile(configFilePath.c_str());
2256 if (!configFile.is_open())
2257 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002258 lg2::error("loadConfigValues: Cannot open config path \'{PATH}\'",
2259 "PATH", configFilePath);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302260 return -1;
2261 }
Zev Weiss1aa08b22021-09-15 17:06:20 -05002262 auto jsonData = nlohmann::json::parse(configFile, nullptr, true, true);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302263
Priyatharshan P70120512020-09-16 18:47:20 +05302264 if (jsonData.is_discarded())
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302265 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002266 lg2::error("Power config readings JSON parser failure");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302267 return -1;
2268 }
Priyatharshan P70120512020-09-16 18:47:20 +05302269 auto gpios = jsonData["gpio_configs"];
2270 auto timers = jsonData["timing_configs"];
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302271
Priyatharshan P70120512020-09-16 18:47:20 +05302272 ConfigData* tempGpioData;
2273
2274 for (nlohmann::json& gpioConfig : gpios)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302275 {
Priyatharshan P70120512020-09-16 18:47:20 +05302276 if (!gpioConfig.contains("Name"))
2277 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002278 lg2::error("The 'Name' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302279 return -1;
2280 }
2281
2282 // Iterate through the powersignal map to check if the gpio json config
2283 // entry is valid
2284 std::string gpioName = gpioConfig["Name"];
2285 auto signalMapIter = powerSignalMap.find(gpioName);
2286 if (signalMapIter == powerSignalMap.end())
2287 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002288 lg2::error(
2289 "{GPIO_NAME} is not a recognized power-control signal name",
2290 "GPIO_NAME", gpioName);
Priyatharshan P70120512020-09-16 18:47:20 +05302291 return -1;
2292 }
2293
2294 // assign the power signal name to the corresponding structure reference
2295 // from map then fillup the structure with coressponding json config
2296 // value
2297 tempGpioData = signalMapIter->second;
2298 tempGpioData->name = gpioName;
2299
2300 if (!gpioConfig.contains("Type"))
2301 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002302 lg2::error("The \'Type\' field must be defined in Json file");
Priyatharshan P70120512020-09-16 18:47:20 +05302303 return -1;
2304 }
2305
2306 std::string signalType = gpioConfig["Type"];
2307 if (signalType == "GPIO")
2308 {
2309 tempGpioData->type = ConfigType::GPIO;
2310 }
2311 else if (signalType == "DBUS")
2312 {
2313 tempGpioData->type = ConfigType::DBUS;
2314 }
2315 else
2316 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002317 lg2::error("{TYPE} is not a recognized power-control signal type",
2318 "TYPE", signalType);
Priyatharshan P70120512020-09-16 18:47:20 +05302319 return -1;
2320 }
2321
2322 if (tempGpioData->type == ConfigType::GPIO)
2323 {
2324 if (gpioConfig.contains("LineName"))
2325 {
2326 tempGpioData->lineName = gpioConfig["LineName"];
2327 }
2328 else
2329 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002330 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002331 "The \'LineName\' field must be defined for GPIO configuration");
Priyatharshan P70120512020-09-16 18:47:20 +05302332 return -1;
2333 }
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002334 if (gpioConfig.contains("Polarity"))
2335 {
2336 std::string polarity = gpioConfig["Polarity"];
2337 if (polarity == "ActiveLow")
2338 {
2339 tempGpioData->polarity = false;
2340 }
2341 else if (polarity == "ActiveHigh")
2342 {
2343 tempGpioData->polarity = true;
2344 }
2345 else
2346 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002347 lg2::error(
2348 "Polarity defined but not properly setup. Please only ActiveHigh or ActiveLow. Currently set to {POLARITY}",
2349 "POLARITY", polarity);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002350 return -1;
2351 }
2352 }
2353 else
2354 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002355 lg2::error("Polarity field not found for {GPIO_NAME}",
2356 "GPIO_NAME", tempGpioData->lineName);
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002357 return -1;
2358 }
Priyatharshan P70120512020-09-16 18:47:20 +05302359 }
2360 else
2361 {
2362 // if dbus based gpio config is defined read and update the dbus
2363 // params corresponding to the gpio config instance
2364 for (auto& [key, dbusParamName] : dbusParams)
2365 {
Logananth Sundararaja4308042021-10-20 11:52:05 +05302366 if (!gpioConfig.contains(dbusParamName))
Priyatharshan P70120512020-09-16 18:47:20 +05302367 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002368 lg2::error(
2369 "The {DBUS_NAME} field must be defined for Dbus configuration ",
2370 "DBUS_NAME", dbusParamName);
Priyatharshan P70120512020-09-16 18:47:20 +05302371 return -1;
2372 }
2373 }
Logananth Sundararaja4308042021-10-20 11:52:05 +05302374 tempGpioData->dbusName =
2375 gpioConfig[dbusParams[DbusConfigType::name]];
2376 tempGpioData->path = gpioConfig[dbusParams[DbusConfigType::path]];
Priyatharshan P70120512020-09-16 18:47:20 +05302377 tempGpioData->interface =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302378 gpioConfig[dbusParams[DbusConfigType::interface]];
Priyatharshan P70120512020-09-16 18:47:20 +05302379 tempGpioData->lineName =
Logananth Sundararaja4308042021-10-20 11:52:05 +05302380 gpioConfig[dbusParams[DbusConfigType::property]];
Priyatharshan P70120512020-09-16 18:47:20 +05302381 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302382 }
2383
Priyatharshan P70120512020-09-16 18:47:20 +05302384 // read and store the timer values from json config to Timer Map
2385 for (auto& [key, timerValue] : TimerMap)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302386 {
Priyatharshan P70120512020-09-16 18:47:20 +05302387 if (timers.contains(key.c_str()))
2388 {
2389 timerValue = timers[key.c_str()];
2390 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302391 }
2392
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302393 return 0;
2394}
Zev Weissa8f116a2021-09-01 21:08:30 -05002395
Patrick Williams439b9c32022-07-22 19:26:53 -05002396static bool getDbusMsgGPIOState(sdbusplus::message_t& msg,
Zev Weissa8f116a2021-09-01 21:08:30 -05002397 const std::string& lineName, bool& value)
2398{
2399 std::string thresholdInterface;
2400 std::string event;
2401 boost::container::flat_map<std::string, std::variant<bool>>
2402 propertiesChanged;
2403 try
2404 {
2405 msg.read(thresholdInterface, propertiesChanged);
2406 if (propertiesChanged.empty())
2407 {
2408 return false;
2409 }
2410
2411 event = propertiesChanged.begin()->first;
2412 if (event.empty() || event != lineName)
2413 {
2414 return false;
2415 }
2416
2417 value = std::get<bool>(propertiesChanged.begin()->second);
2418 return true;
2419 }
Patrick Williamsf3a33b42021-10-06 12:37:26 -05002420 catch (const std::exception& e)
Zev Weissa8f116a2021-09-01 21:08:30 -05002421 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002422 lg2::error(
2423 "exception while reading dbus property \'{DBUS_NAME}\': {ERROR}",
2424 "DBUS_NAME", lineName, "ERROR", e);
Zev Weissa8f116a2021-09-01 21:08:30 -05002425 return false;
2426 }
2427}
2428
Patrick Williams439b9c32022-07-22 19:26:53 -05002429static sdbusplus::bus::match_t
Zev Weissa8f116a2021-09-01 21:08:30 -05002430 dbusGPIOMatcher(const ConfigData& cfg, std::function<void(bool)> onMatch)
2431{
Patrick Williams439b9c32022-07-22 19:26:53 -05002432 auto pulseEventMatcherCallback = [&cfg,
2433 onMatch](sdbusplus::message_t& msg) {
2434 bool value = false;
2435 if (!getDbusMsgGPIOState(msg, cfg.lineName, value))
2436 {
2437 return;
2438 }
2439 onMatch(value);
2440 };
Zev Weissa8f116a2021-09-01 21:08:30 -05002441
Patrick Williams439b9c32022-07-22 19:26:53 -05002442 return sdbusplus::bus::match_t(
2443 static_cast<sdbusplus::bus_t&>(*conn),
Zev Weissa8f116a2021-09-01 21:08:30 -05002444 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2445 "PropertiesChanged',arg0='" +
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302446 cfg.interface + "'",
Zev Weissa8f116a2021-09-01 21:08:30 -05002447 std::move(pulseEventMatcherCallback));
2448}
2449
Priyatharshan P70120512020-09-16 18:47:20 +05302450int getProperty(ConfigData& configData)
2451{
2452 auto method = conn->new_method_call(
2453 configData.dbusName.c_str(), configData.path.c_str(),
2454 "org.freedesktop.DBus.Properties", "Get");
2455 method.append(configData.interface.c_str(), configData.lineName.c_str());
2456
2457 auto reply = conn->call(method);
2458 if (reply.is_method_error())
2459 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002460 lg2::error(
2461 "Error reading {PROPERTY} D-Bus property on interface {INTERFACE} and path {PATH}",
2462 "PROPERTY", configData.lineName, "INTERFACE", configData.interface,
2463 "PATH", configData.path);
Priyatharshan P70120512020-09-16 18:47:20 +05302464 return -1;
2465 }
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302466 std::variant<bool> resp;
Priyatharshan P70120512020-09-16 18:47:20 +05302467 reply.read(resp);
Logananth Sundararaj85e111e2021-11-11 13:13:13 +05302468 auto respValue = std::get_if<bool>(&resp);
Priyatharshan P70120512020-09-16 18:47:20 +05302469 if (!respValue)
2470 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002471 lg2::error("Error: {PROPERTY} D-Bus property is not the expected type",
2472 "PROPERTY", configData.lineName);
Priyatharshan P70120512020-09-16 18:47:20 +05302473 return -1;
2474 }
2475 return (*respValue);
2476}
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002477} // namespace power_control
2478
2479int main(int argc, char* argv[])
2480{
Lei YU92caa4c2021-02-23 16:59:25 +08002481 using namespace power_control;
Priyatharshan P70120512020-09-16 18:47:20 +05302482
2483 if (argc > 1)
2484 {
2485 node = argv[1];
2486 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002487 lg2::info("Start Chassis power control service for host : {NODE}", "NODE",
2488 node);
Priyatharshan P70120512020-09-16 18:47:20 +05302489
Lei YU92caa4c2021-02-23 16:59:25 +08002490 conn = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002491
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302492 // Load GPIO's through json config file
Lei YU92caa4c2021-02-23 16:59:25 +08002493 if (loadConfigValues() == -1)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302494 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002495 lg2::error("Host{NODE}: Error in Parsing...", "NODE", node);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302496 }
Naveen Mosesec972d82021-07-16 21:19:23 +05302497 /* Currently for single host based systems additional busname is added
2498 with "0" at the end of the name ex : xyz.openbmc_project.State.Host0.
2499 Going forward for single hosts the old bus name without zero numbering
2500 will be removed when all other applications adapted to the
2501 bus name with zero numbering (xyz.openbmc_project.State.Host0). */
2502
2503 if (node == "0")
2504 {
2505 // Request all the dbus names
2506 conn->request_name(hostDbusName.c_str());
2507 conn->request_name(chassisDbusName.c_str());
2508 conn->request_name(osDbusName.c_str());
2509 conn->request_name(buttonDbusName.c_str());
2510 conn->request_name(nmiDbusName.c_str());
2511 conn->request_name(rstCauseDbusName.c_str());
2512 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302513
Zev Weissc4005bd2021-09-01 22:30:23 -05002514 hostDbusName += node;
2515 chassisDbusName += node;
2516 osDbusName += node;
2517 buttonDbusName += node;
2518 nmiDbusName += node;
2519 rstCauseDbusName += node;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002520
Priyatharshan P70120512020-09-16 18:47:20 +05302521 // Request all the dbus names
2522 conn->request_name(hostDbusName.c_str());
2523 conn->request_name(chassisDbusName.c_str());
2524 conn->request_name(osDbusName.c_str());
2525 conn->request_name(buttonDbusName.c_str());
2526 conn->request_name(nmiDbusName.c_str());
2527 conn->request_name(rstCauseDbusName.c_str());
2528
2529 if (sioPwrGoodConfig.lineName.empty() ||
2530 sioOnControlConfig.lineName.empty() || sioS5Config.lineName.empty())
Priyatharshan P19c47a32020-08-12 18:16:43 +05302531 {
Lei YU92caa4c2021-02-23 16:59:25 +08002532 sioEnabled = false;
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002533 lg2::info("SIO control GPIOs not defined, disable SIO support.");
Priyatharshan P19c47a32020-08-12 18:16:43 +05302534 }
2535
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002536 // Request PS_PWROK GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302537 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002538 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002539 if (!requestGPIOEvents(powerOkConfig.lineName, psPowerOKHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302540 psPowerOKLine, psPowerOKEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302541 {
2542 return -1;
2543 }
2544 }
Priyatharshan P70120512020-09-16 18:47:20 +05302545 else if (powerOkConfig.type == ConfigType::DBUS)
2546 {
2547
Patrick Williams439b9c32022-07-22 19:26:53 -05002548 static sdbusplus::bus::match_t powerOkEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002549 power_control::dbusGPIOMatcher(powerOkConfig, psPowerOKHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302550 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302551 else
2552 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002553 lg2::error("PowerOk name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002554 return -1;
2555 }
2556
Lei YU92caa4c2021-02-23 16:59:25 +08002557 if (sioEnabled == true)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002558 {
Priyatharshan P19c47a32020-08-12 18:16:43 +05302559 // Request SIO_POWER_GOOD GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302560 if (sioPwrGoodConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302561 {
Priyatharshan P70120512020-09-16 18:47:20 +05302562 if (!requestGPIOEvents(sioPwrGoodConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002563 sioPowerGoodHandler, sioPowerGoodLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302564 sioPowerGoodEvent))
2565 {
2566 return -1;
2567 }
2568 }
2569 else if (sioPwrGoodConfig.type == ConfigType::DBUS)
2570 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002571 static sdbusplus::bus::match_t sioPwrGoodEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002572 power_control::dbusGPIOMatcher(sioPwrGoodConfig,
2573 sioPowerGoodHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302574 }
2575 else
2576 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002577 lg2::error(
Priyatharshan P70120512020-09-16 18:47:20 +05302578 "sioPwrGood name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302579 return -1;
2580 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002581
Priyatharshan P19c47a32020-08-12 18:16:43 +05302582 // Request SIO_ONCONTROL GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302583 if (sioOnControlConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302584 {
Priyatharshan P70120512020-09-16 18:47:20 +05302585 if (!requestGPIOEvents(sioOnControlConfig.lineName,
Zev Weiss676ef2c2021-09-02 21:54:02 -05002586 sioOnControlHandler, sioOnControlLine,
Priyatharshan P70120512020-09-16 18:47:20 +05302587 sioOnControlEvent))
2588 {
2589 return -1;
2590 }
2591 }
2592 else if (sioOnControlConfig.type == ConfigType::DBUS)
2593 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002594 static sdbusplus::bus::match_t sioOnControlEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002595 power_control::dbusGPIOMatcher(sioOnControlConfig,
2596 sioOnControlHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302597 }
2598 else
2599 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002600 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07002601 "sioOnControl name should be configured from jsonconfig file\n");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302602 return -1;
2603 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002604
Priyatharshan P19c47a32020-08-12 18:16:43 +05302605 // Request SIO_S5 GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302606 if (sioS5Config.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302607 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002608 if (!requestGPIOEvents(sioS5Config.lineName, sioS5Handler,
Priyatharshan P70120512020-09-16 18:47:20 +05302609 sioS5Line, sioS5Event))
2610 {
2611 return -1;
2612 }
2613 }
2614 else if (sioS5Config.type == ConfigType::DBUS)
2615 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002616 static sdbusplus::bus::match_t sioS5EventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002617 power_control::dbusGPIOMatcher(sioS5Config, sioS5Handler);
Priyatharshan P70120512020-09-16 18:47:20 +05302618 }
2619 else
2620 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002621 lg2::error("sioS5 name should be configured from json config file");
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302622 return -1;
2623 }
2624 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002625
2626 // Request POWER_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302627 if (powerButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002628 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002629 if (!requestGPIOEvents(powerButtonConfig.lineName, powerButtonHandler,
2630 powerButtonLine, powerButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302631 {
2632 return -1;
2633 }
2634 }
Priyatharshan P70120512020-09-16 18:47:20 +05302635 else if (powerButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302636 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002637 static sdbusplus::bus::match_t powerButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002638 power_control::dbusGPIOMatcher(powerButtonConfig,
2639 powerButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002640 }
2641
2642 // Request RESET_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302643 if (resetButtonConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002644 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002645 if (!requestGPIOEvents(resetButtonConfig.lineName, resetButtonHandler,
2646 resetButtonLine, resetButtonEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302647 {
2648 return -1;
2649 }
2650 }
Priyatharshan P70120512020-09-16 18:47:20 +05302651 else if (resetButtonConfig.type == ConfigType::DBUS)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302652 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002653 static sdbusplus::bus::match_t resetButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002654 power_control::dbusGPIOMatcher(resetButtonConfig,
2655 resetButtonHandler);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002656 }
2657
2658 // Request NMI_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302659 if (nmiButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302660 {
Priyatharshan P70120512020-09-16 18:47:20 +05302661 if (!nmiButtonConfig.lineName.empty())
2662 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002663 requestGPIOEvents(nmiButtonConfig.lineName, nmiButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302664 nmiButtonLine, nmiButtonEvent);
2665 }
2666 }
2667 else if (nmiButtonConfig.type == ConfigType::DBUS)
2668 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002669 static sdbusplus::bus::match_t nmiButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002670 power_control::dbusGPIOMatcher(nmiButtonConfig, nmiButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302671 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002672
2673 // Request ID_BUTTON GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302674 if (idButtonConfig.type == ConfigType::GPIO)
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302675 {
Priyatharshan P70120512020-09-16 18:47:20 +05302676 if (!idButtonConfig.lineName.empty())
2677 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002678 requestGPIOEvents(idButtonConfig.lineName, idButtonHandler,
Priyatharshan P70120512020-09-16 18:47:20 +05302679 idButtonLine, idButtonEvent);
2680 }
2681 }
2682 else if (idButtonConfig.type == ConfigType::DBUS)
2683 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002684 static sdbusplus::bus::match_t idButtonEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002685 power_control::dbusGPIOMatcher(idButtonConfig, idButtonHandler);
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302686 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002687
Jason M. Billsfb957332021-01-28 13:18:46 -08002688#ifdef USE_PLT_RST
Patrick Williams439b9c32022-07-22 19:26:53 -05002689 sdbusplus::bus::match_t pltRstMatch(
Lei YU92caa4c2021-02-23 16:59:25 +08002690 *conn,
Jason M. Billsfb957332021-01-28 13:18:46 -08002691 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
2692 "PropertiesChanged',arg0='xyz.openbmc_project.State.Host.Misc'",
Lei YU92caa4c2021-02-23 16:59:25 +08002693 hostMiscHandler);
Jason M. Billsfb957332021-01-28 13:18:46 -08002694#endif
2695
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002696 // Request POST_COMPLETE GPIO events
Priyatharshan P70120512020-09-16 18:47:20 +05302697 if (postCompleteConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002698 {
Zev Weiss676ef2c2021-09-02 21:54:02 -05002699 if (!requestGPIOEvents(postCompleteConfig.lineName, postCompleteHandler,
2700 postCompleteLine, postCompleteEvent))
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302701 {
2702 return -1;
2703 }
2704 }
Priyatharshan P70120512020-09-16 18:47:20 +05302705 else if (postCompleteConfig.type == ConfigType::DBUS)
2706 {
Patrick Williams439b9c32022-07-22 19:26:53 -05002707 static sdbusplus::bus::match_t postCompleteEventMonitor =
Zev Weiss584aa132021-09-02 19:21:52 -05002708 power_control::dbusGPIOMatcher(postCompleteConfig,
2709 postCompleteHandler);
Priyatharshan P70120512020-09-16 18:47:20 +05302710 }
Priyatharshan Pe4d7f2b2020-06-22 22:41:42 +05302711 else
2712 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002713 lg2::error(
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002714 "postComplete name should be configured from json config file");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002715 return -1;
2716 }
2717
2718 // initialize NMI_OUT GPIO.
Priyatharshan P70120512020-09-16 18:47:20 +05302719 if (!nmiOutConfig.lineName.empty())
2720 {
Jian Zhang461a1662022-09-22 11:29:01 +08002721 setGPIOOutput(nmiOutConfig.lineName, !nmiOutConfig.polarity,
2722 nmiOutLine);
Priyatharshan P70120512020-09-16 18:47:20 +05302723 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002724
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002725 // Initialize POWER_OUT and RESET_OUT GPIO.
2726 gpiod::line line;
Priyatharshan P70120512020-09-16 18:47:20 +05302727 if (!powerOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002728 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002729 if (!setGPIOOutput(powerOutConfig.lineName, !powerOutConfig.polarity,
2730 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302731 {
2732 return -1;
2733 }
2734 }
2735 else
2736 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002737 lg2::error("powerOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002738 return -1;
2739 }
2740
Priyatharshan P70120512020-09-16 18:47:20 +05302741 if (!resetOutConfig.lineName.empty())
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002742 {
Jean-Marie Verdun50937e72021-08-31 09:15:49 -07002743 if (!setGPIOOutput(resetOutConfig.lineName, !resetOutConfig.polarity,
2744 line))
Priyatharshan P70120512020-09-16 18:47:20 +05302745 {
2746 return -1;
2747 }
2748 }
2749 else
2750 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002751 lg2::error("ResetOut name should be configured from json config file");
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002752 return -1;
2753 }
Vijay Khemka0dc7d4c2019-10-22 12:30:17 -07002754 // Release line
2755 line.reset();
2756
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002757 // Initialize the power state
Lei YU92caa4c2021-02-23 16:59:25 +08002758 powerState = PowerState::off;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002759 // Check power good
Priyatharshan P70120512020-09-16 18:47:20 +05302760
2761 if (powerOkConfig.type == ConfigType::GPIO)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002762 {
Jean-Marie Verdun61b4a5b2021-09-19 08:53:28 -04002763 if (psPowerOKLine.get_value() > 0 ||
Lei YUa37c2472021-09-26 15:57:12 +08002764 (sioEnabled &&
2765 (sioPowerGoodLine.get_value() == sioPwrGoodConfig.polarity)))
Priyatharshan P70120512020-09-16 18:47:20 +05302766 {
2767 powerState = PowerState::on;
2768 }
2769 }
2770 else
2771 {
2772 if (getProperty(powerOkConfig))
2773 {
2774 powerState = PowerState::on;
2775 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002776 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002777 // Check if we need to start the Power Restore policy
Andrei Kartashev99e8f9d2022-01-09 12:15:05 +03002778 if (powerState != PowerState::on)
2779 {
2780 powerRestore.run();
2781 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002782
Lei YU92caa4c2021-02-23 16:59:25 +08002783 if (nmiOutLine)
2784 nmiSourcePropertyMonitor();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002785
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002786 lg2::info("Initializing power state.");
Lei YU92caa4c2021-02-23 16:59:25 +08002787 logStateTransition(powerState);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002788
2789 // Power Control Service
2790 sdbusplus::asio::object_server hostServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002791 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002792
2793 // Power Control Interface
Priyatharshan P70120512020-09-16 18:47:20 +05302794 hostIface =
2795 hostServer.add_interface("/xyz/openbmc_project/state/host" + node,
2796 "xyz.openbmc_project.State.Host");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002797 // Interface for IPMI/Redfish initiated host state transitions
Lei YU92caa4c2021-02-23 16:59:25 +08002798 hostIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002799 "RequestedHostTransition",
2800 std::string("xyz.openbmc_project.State.Host.Transition.Off"),
2801 [](const std::string& requested, std::string& resp) {
2802 if (requested == "xyz.openbmc_project.State.Host.Transition.Off")
2803 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002804 // if power button is masked, ignore this
2805 if (!powerButtonMask)
2806 {
2807 sendPowerControlEvent(Event::gracefulPowerOffRequest);
2808 addRestartCause(RestartCause::command);
2809 }
2810 else
2811 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002812 lg2::info("Power Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002813 throw std::invalid_argument("Transition Request Masked");
2814 return 0;
2815 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002816 }
2817 else if (requested ==
2818 "xyz.openbmc_project.State.Host.Transition.On")
2819 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002820 // if power button is masked, ignore this
2821 if (!powerButtonMask)
2822 {
2823 sendPowerControlEvent(Event::powerOnRequest);
2824 addRestartCause(RestartCause::command);
2825 }
2826 else
2827 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002828 lg2::info("Power Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002829 throw std::invalid_argument("Transition Request Masked");
2830 return 0;
2831 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002832 }
2833 else if (requested ==
2834 "xyz.openbmc_project.State.Host.Transition.Reboot")
2835 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002836 // if power button is masked, ignore this
2837 if (!powerButtonMask)
2838 {
2839 sendPowerControlEvent(Event::powerCycleRequest);
2840 addRestartCause(RestartCause::command);
2841 }
2842 else
2843 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002844 lg2::info("Power Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002845 throw std::invalid_argument("Transition Request Masked");
2846 return 0;
2847 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002848 }
Jason M. Bills418ce112021-09-08 15:15:05 -07002849 else if (
2850 requested ==
2851 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot")
Jason M. Billse7520ba2020-01-31 11:19:03 -08002852 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002853 // if reset button is masked, ignore this
2854 if (!resetButtonMask)
2855 {
2856 sendPowerControlEvent(Event::gracefulPowerCycleRequest);
2857 addRestartCause(RestartCause::command);
2858 }
2859 else
2860 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002861 lg2::info("Reset Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002862 throw std::invalid_argument("Transition Request Masked");
2863 return 0;
2864 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002865 }
Jason M. Bills418ce112021-09-08 15:15:05 -07002866 else if (
2867 requested ==
2868 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot")
Jason M. Billse7520ba2020-01-31 11:19:03 -08002869 {
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002870 // if reset button is masked, ignore this
2871 if (!resetButtonMask)
2872 {
2873 sendPowerControlEvent(Event::resetRequest);
2874 addRestartCause(RestartCause::command);
2875 }
2876 else
2877 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002878 lg2::info("Reset Button Masked.");
Vernon Maueryb4d03b12021-05-26 19:11:41 -07002879 throw std::invalid_argument("Transition Request Masked");
2880 return 0;
2881 }
Jason M. Billse7520ba2020-01-31 11:19:03 -08002882 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002883 else
2884 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002885 lg2::error("Unrecognized host state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002886 throw std::invalid_argument("Unrecognized Transition Request");
2887 return 0;
2888 }
2889 resp = requested;
2890 return 1;
2891 });
Lei YU92caa4c2021-02-23 16:59:25 +08002892 hostIface->register_property("CurrentHostState",
2893 std::string(getHostState(powerState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002894
Lei YU92caa4c2021-02-23 16:59:25 +08002895 hostIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002896
2897 // Chassis Control Service
2898 sdbusplus::asio::object_server chassisServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002899 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002900
2901 // Chassis Control Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002902 chassisIface =
Priyatharshan P70120512020-09-16 18:47:20 +05302903 chassisServer.add_interface("/xyz/openbmc_project/state/chassis" + node,
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002904 "xyz.openbmc_project.State.Chassis");
2905
Lei YU92caa4c2021-02-23 16:59:25 +08002906 chassisIface->register_property(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002907 "RequestedPowerTransition",
2908 std::string("xyz.openbmc_project.State.Chassis.Transition.Off"),
2909 [](const std::string& requested, std::string& resp) {
2910 if (requested == "xyz.openbmc_project.State.Chassis.Transition.Off")
2911 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002912 // if power button is masked, ignore this
2913 if (!powerButtonMask)
2914 {
2915 sendPowerControlEvent(Event::powerOffRequest);
2916 addRestartCause(RestartCause::command);
2917 }
2918 else
2919 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002920 lg2::info("Power Button Masked.");
Vernon Mauery2a269432021-07-14 10:00:21 -07002921 throw std::invalid_argument("Transition Request Masked");
2922 return 0;
2923 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002924 }
2925 else if (requested ==
2926 "xyz.openbmc_project.State.Chassis.Transition.On")
2927 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002928 // if power button is masked, ignore this
2929 if (!powerButtonMask)
2930 {
2931 sendPowerControlEvent(Event::powerOnRequest);
2932 addRestartCause(RestartCause::command);
2933 }
2934 else
2935 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002936 lg2::info("Power Button Masked.");
Vernon Mauery2a269432021-07-14 10:00:21 -07002937 throw std::invalid_argument("Transition Request Masked");
2938 return 0;
2939 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002940 }
2941 else if (requested ==
2942 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2943 {
Vernon Mauery2a269432021-07-14 10:00:21 -07002944 // if power button is masked, ignore this
2945 if (!powerButtonMask)
2946 {
2947 sendPowerControlEvent(Event::powerCycleRequest);
2948 addRestartCause(RestartCause::command);
2949 }
2950 else
2951 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002952 lg2::info("Power Button Masked.");
Vernon Mauery2a269432021-07-14 10:00:21 -07002953 throw std::invalid_argument("Transition Request Masked");
2954 return 0;
2955 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002956 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002957 else
2958 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002959 lg2::error("Unrecognized chassis state transition request.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002960 throw std::invalid_argument("Unrecognized Transition Request");
2961 return 0;
2962 }
2963 resp = requested;
2964 return 1;
2965 });
Lei YU92caa4c2021-02-23 16:59:25 +08002966 chassisIface->register_property("CurrentPowerState",
2967 std::string(getChassisState(powerState)));
2968 chassisIface->register_property("LastStateChangeTime", getCurrentTimeMs());
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002969
Lei YU92caa4c2021-02-23 16:59:25 +08002970 chassisIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07002971
Vijay Khemka04175c22020-10-09 14:28:11 -07002972#ifdef CHASSIS_SYSTEM_RESET
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002973 // Chassis System Service
2974 sdbusplus::asio::object_server chassisSysServer =
Lei YU92caa4c2021-02-23 16:59:25 +08002975 sdbusplus::asio::object_server(conn);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002976
2977 // Chassis System Interface
Lei YU92caa4c2021-02-23 16:59:25 +08002978 chassisSysIface = chassisSysServer.add_interface(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002979 "/xyz/openbmc_project/state/chassis_system0",
2980 "xyz.openbmc_project.State.Chassis");
2981
Lei YU92caa4c2021-02-23 16:59:25 +08002982 chassisSysIface->register_property(
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002983 "RequestedPowerTransition",
2984 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
2985 [](const std::string& requested, std::string& resp) {
2986 if (requested ==
2987 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
2988 {
Lei YU92caa4c2021-02-23 16:59:25 +08002989 systemReset();
2990 addRestartCause(RestartCause::command);
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002991 }
2992 else
2993 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08002994 lg2::error(
Jason M. Bills41a49aa2021-03-03 16:03:25 -08002995 "Unrecognized chassis system state transition request.");
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07002996 throw std::invalid_argument("Unrecognized Transition Request");
2997 return 0;
2998 }
2999 resp = requested;
3000 return 1;
3001 });
Lei YU92caa4c2021-02-23 16:59:25 +08003002 chassisSysIface->register_property(
3003 "CurrentPowerState", std::string(getChassisState(powerState)));
3004 chassisSysIface->register_property("LastStateChangeTime",
3005 getCurrentTimeMs());
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003006
Lei YU92caa4c2021-02-23 16:59:25 +08003007 chassisSysIface->initialize();
Vijay Khemka75ad0cf2020-04-02 15:23:51 -07003008
Naveen Moses117c34e2021-05-26 20:10:51 +05303009 if (!slotPowerConfig.lineName.empty())
3010 {
3011 if (!setGPIOOutput(slotPowerConfig.lineName, 1, slotPowerLine))
3012 {
3013 return -1;
3014 }
3015
3016 slotPowerState = SlotPowerState::off;
3017 if (slotPowerLine.get_value() > 0)
3018 {
3019 slotPowerState = SlotPowerState::on;
3020 }
3021
3022 chassisSlotIface = chassisSysServer.add_interface(
3023 "/xyz/openbmc_project/state/chassis_system" + node,
3024 "xyz.openbmc_project.State.Chassis");
3025 chassisSlotIface->register_property(
3026 "RequestedPowerTransition",
3027 std::string("xyz.openbmc_project.State.Chassis.Transition.On"),
3028 [](const std::string& requested, std::string& resp) {
3029 if (requested ==
3030 "xyz.openbmc_project.State.Chassis.Transition.On")
3031 {
3032 slotPowerOn();
3033 }
3034 else if (requested ==
3035 "xyz.openbmc_project.State.Chassis.Transition.Off")
3036 {
3037 slotPowerOff();
3038 }
Jason M. Bills418ce112021-09-08 15:15:05 -07003039 else if (
3040 requested ==
3041 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle")
Naveen Moses117c34e2021-05-26 20:10:51 +05303042 {
3043 slotPowerCycle();
3044 }
3045 else
3046 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003047 lg2::error(
Jason M. Bills418ce112021-09-08 15:15:05 -07003048 "Unrecognized chassis system state transition request.\n");
Naveen Moses117c34e2021-05-26 20:10:51 +05303049 throw std::invalid_argument(
3050 "Unrecognized Transition Request");
3051 return 0;
3052 }
3053 resp = requested;
3054 return 1;
3055 });
3056 chassisSlotIface->register_property(
3057 "CurrentPowerState", std::string(getSlotState(slotPowerState)));
3058 chassisSlotIface->register_property("LastStateChangeTime",
3059 getCurrentTimeMs());
3060 chassisSlotIface->initialize();
3061 }
3062#endif
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003063 // Buttons Service
3064 sdbusplus::asio::object_server buttonsServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003065 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003066
Priyatharshan P70120512020-09-16 18:47:20 +05303067 if (!powerButtonConfig.lineName.empty())
John Wang6c090072020-09-30 13:32:16 +08003068 {
Priyatharshan P70120512020-09-16 18:47:20 +05303069 // Power Button Interface
3070 power_control::powerButtonIface = buttonsServer.add_interface(
3071 "/xyz/openbmc_project/chassis/buttons/power",
3072 "xyz.openbmc_project.Chassis.Buttons");
3073
3074 powerButtonIface->register_property(
3075 "ButtonMasked", false, [](const bool requested, bool& current) {
3076 if (requested)
3077 {
3078 if (powerButtonMask)
3079 {
3080 return 1;
3081 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003082 if (!setGPIOOutput(powerOutConfig.lineName,
3083 !powerOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303084 powerButtonMask))
3085 {
3086 throw std::runtime_error("Failed to request GPIO");
3087 return 0;
3088 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003089 lg2::info("Power Button Masked.");
Priyatharshan P70120512020-09-16 18:47:20 +05303090 }
3091 else
3092 {
3093 if (!powerButtonMask)
3094 {
3095 return 1;
3096 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003097 lg2::info("Power Button Un-masked");
Priyatharshan P70120512020-09-16 18:47:20 +05303098 powerButtonMask.reset();
3099 }
3100 // Update the mask setting
3101 current = requested;
3102 return 1;
3103 });
3104
3105 // Check power button state
3106 bool powerButtonPressed;
3107 if (powerButtonConfig.type == ConfigType::GPIO)
3108 {
3109 powerButtonPressed = powerButtonLine.get_value() == 0;
3110 }
3111 else
3112 {
3113 powerButtonPressed = getProperty(powerButtonConfig) == 0;
3114 }
3115
3116 powerButtonIface->register_property("ButtonPressed",
3117 powerButtonPressed);
3118
3119 powerButtonIface->initialize();
3120 }
3121
3122 if (!resetButtonConfig.lineName.empty())
3123 {
3124 // Reset Button Interface
3125
Lei YU92caa4c2021-02-23 16:59:25 +08003126 resetButtonIface = buttonsServer.add_interface(
John Wang6c090072020-09-30 13:32:16 +08003127 "/xyz/openbmc_project/chassis/buttons/reset",
3128 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003129
Lei YU92caa4c2021-02-23 16:59:25 +08003130 resetButtonIface->register_property(
John Wang6c090072020-09-30 13:32:16 +08003131 "ButtonMasked", false, [](const bool requested, bool& current) {
3132 if (requested)
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003133 {
Lei YU92caa4c2021-02-23 16:59:25 +08003134 if (resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003135 {
3136 return 1;
3137 }
Jean-Marie Verdun2c495cf2021-09-17 21:42:23 -04003138 if (!setGPIOOutput(resetOutConfig.lineName,
3139 !resetOutConfig.polarity,
Priyatharshan P70120512020-09-16 18:47:20 +05303140 resetButtonMask))
John Wang6c090072020-09-30 13:32:16 +08003141 {
3142 throw std::runtime_error("Failed to request GPIO");
3143 return 0;
3144 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003145 lg2::info("Reset Button Masked.");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003146 }
John Wang6c090072020-09-30 13:32:16 +08003147 else
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003148 {
Lei YU92caa4c2021-02-23 16:59:25 +08003149 if (!resetButtonMask)
John Wang6c090072020-09-30 13:32:16 +08003150 {
3151 return 1;
3152 }
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003153 lg2::info("Reset Button Un-masked");
Lei YU92caa4c2021-02-23 16:59:25 +08003154 resetButtonMask.reset();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003155 }
John Wang6c090072020-09-30 13:32:16 +08003156 // Update the mask setting
3157 current = requested;
3158 return 1;
3159 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003160
John Wang6c090072020-09-30 13:32:16 +08003161 // Check reset button state
Priyatharshan P70120512020-09-16 18:47:20 +05303162 bool resetButtonPressed;
3163 if (resetButtonConfig.type == ConfigType::GPIO)
3164 {
3165 resetButtonPressed = resetButtonLine.get_value() == 0;
3166 }
3167 else
3168 {
3169 resetButtonPressed = getProperty(resetButtonConfig) == 0;
3170 }
3171
Lei YU92caa4c2021-02-23 16:59:25 +08003172 resetButtonIface->register_property("ButtonPressed",
3173 resetButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003174
Lei YU92caa4c2021-02-23 16:59:25 +08003175 resetButtonIface->initialize();
John Wang6c090072020-09-30 13:32:16 +08003176 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003177
Lei YU92caa4c2021-02-23 16:59:25 +08003178 if (nmiButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003179 {
3180 // NMI Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003181 nmiButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003182 "/xyz/openbmc_project/chassis/buttons/nmi",
3183 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003184
Lei YU92caa4c2021-02-23 16:59:25 +08003185 nmiButtonIface->register_property(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003186 "ButtonMasked", false, [](const bool requested, bool& current) {
Lei YU92caa4c2021-02-23 16:59:25 +08003187 if (nmiButtonMasked == requested)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003188 {
3189 // NMI button mask is already set as requested, so no change
3190 return 1;
3191 }
3192 if (requested)
3193 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003194 lg2::info("NMI Button Masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003195 nmiButtonMasked = true;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003196 }
3197 else
3198 {
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003199 lg2::info("NMI Button Un-masked.");
Lei YU92caa4c2021-02-23 16:59:25 +08003200 nmiButtonMasked = false;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003201 }
3202 // Update the mask setting
Lei YU92caa4c2021-02-23 16:59:25 +08003203 current = nmiButtonMasked;
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003204 return 1;
Vijay Khemka33a532d2019-11-14 16:50:35 -08003205 });
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003206
Vijay Khemka33a532d2019-11-14 16:50:35 -08003207 // Check NMI button state
Priyatharshan P70120512020-09-16 18:47:20 +05303208 bool nmiButtonPressed;
3209 if (nmiButtonConfig.type == ConfigType::GPIO)
3210 {
3211 nmiButtonPressed = nmiButtonLine.get_value() == 0;
3212 }
3213 else
3214 {
3215 nmiButtonPressed = getProperty(nmiButtonConfig) == 0;
3216 }
3217
Lei YU92caa4c2021-02-23 16:59:25 +08003218 nmiButtonIface->register_property("ButtonPressed", nmiButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003219
Lei YU92caa4c2021-02-23 16:59:25 +08003220 nmiButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003221 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003222
Lei YU92caa4c2021-02-23 16:59:25 +08003223 if (nmiOutLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003224 {
3225 // NMI out Service
3226 sdbusplus::asio::object_server nmiOutServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003227 sdbusplus::asio::object_server(conn);
Chen Yugang174ec662019-08-19 19:58:49 +08003228
Vijay Khemka33a532d2019-11-14 16:50:35 -08003229 // NMI out Interface
Priyatharshan P70120512020-09-16 18:47:20 +05303230 nmiOutIface = nmiOutServer.add_interface(
3231 "/xyz/openbmc_project/control/host" + node + "/nmi",
3232 "xyz.openbmc_project.Control.Host.NMI");
Lei YU92caa4c2021-02-23 16:59:25 +08003233 nmiOutIface->register_method("NMI", nmiReset);
3234 nmiOutIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003235 }
Chen Yugang174ec662019-08-19 19:58:49 +08003236
Lei YU92caa4c2021-02-23 16:59:25 +08003237 if (idButtonLine)
Vijay Khemka33a532d2019-11-14 16:50:35 -08003238 {
3239 // ID Button Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003240 idButtonIface = buttonsServer.add_interface(
Vijay Khemka33a532d2019-11-14 16:50:35 -08003241 "/xyz/openbmc_project/chassis/buttons/id",
3242 "xyz.openbmc_project.Chassis.Buttons");
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003243
Vijay Khemka33a532d2019-11-14 16:50:35 -08003244 // Check ID button state
Priyatharshan P70120512020-09-16 18:47:20 +05303245 bool idButtonPressed;
3246 if (idButtonConfig.type == ConfigType::GPIO)
3247 {
3248 idButtonPressed = idButtonLine.get_value() == 0;
3249 }
3250 else
3251 {
3252 idButtonPressed = getProperty(idButtonConfig) == 0;
3253 }
3254
Lei YU92caa4c2021-02-23 16:59:25 +08003255 idButtonIface->register_property("ButtonPressed", idButtonPressed);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003256
Lei YU92caa4c2021-02-23 16:59:25 +08003257 idButtonIface->initialize();
Vijay Khemka33a532d2019-11-14 16:50:35 -08003258 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003259
3260 // OS State Service
3261 sdbusplus::asio::object_server osServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003262 sdbusplus::asio::object_server(conn);
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003263
3264 // OS State Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003265 osIface = osServer.add_interface(
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003266 "/xyz/openbmc_project/state/os",
3267 "xyz.openbmc_project.State.OperatingSystem.Status");
3268
3269 // Get the initial OS state based on POST complete
3270 // 0: Asserted, OS state is "Standby" (ready to boot)
3271 // 1: De-Asserted, OS state is "Inactive"
Tim Lee86239182021-12-23 11:46:01 +08003272 OperatingSystemStateStage osState;
Priyatharshan P70120512020-09-16 18:47:20 +05303273 if (postCompleteConfig.type == ConfigType::GPIO)
3274 {
Tim Lee86239182021-12-23 11:46:01 +08003275 osState = postCompleteLine.get_value() > 0
3276 ? OperatingSystemStateStage::Inactive
3277 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303278 }
3279 else
3280 {
Tim Lee86239182021-12-23 11:46:01 +08003281 osState = getProperty(postCompleteConfig) > 0
3282 ? OperatingSystemStateStage::Inactive
3283 : OperatingSystemStateStage::Standby;
Priyatharshan P70120512020-09-16 18:47:20 +05303284 }
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003285
Tim Lee86239182021-12-23 11:46:01 +08003286 osIface->register_property(
3287 "OperatingSystemState",
3288 std::string(getOperatingSystemStateStage(osState)));
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003289
Lei YU92caa4c2021-02-23 16:59:25 +08003290 osIface->initialize();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003291
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003292 // Restart Cause Service
3293 sdbusplus::asio::object_server restartCauseServer =
Lei YU92caa4c2021-02-23 16:59:25 +08003294 sdbusplus::asio::object_server(conn);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003295
3296 // Restart Cause Interface
Lei YU92caa4c2021-02-23 16:59:25 +08003297 restartCauseIface = restartCauseServer.add_interface(
Naveen Mosesec972d82021-07-16 21:19:23 +05303298 "/xyz/openbmc_project/control/host" + node + "/restart_cause",
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003299 "xyz.openbmc_project.Control.Host.RestartCause");
3300
Lei YU92caa4c2021-02-23 16:59:25 +08003301 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003302 "RestartCause",
3303 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"));
3304
Lei YU92caa4c2021-02-23 16:59:25 +08003305 restartCauseIface->register_property(
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003306 "RequestedRestartCause",
3307 std::string("xyz.openbmc_project.State.Host.RestartCause.Unknown"),
3308 [](const std::string& requested, std::string& resp) {
3309 if (requested ==
3310 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
3311 {
Lei YU92caa4c2021-02-23 16:59:25 +08003312 addRestartCause(RestartCause::watchdog);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003313 }
3314 else
3315 {
3316 throw std::invalid_argument(
3317 "Unrecognized RestartCause Request");
3318 return 0;
3319 }
3320
Jason M. Billsc46ebb42021-11-10 11:41:31 -08003321 lg2::info("RestartCause requested: {RESTART_CAUSE}",
3322 "RESTART_CAUSE", requested);
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003323 resp = requested;
3324 return 1;
3325 });
3326
Lei YU92caa4c2021-02-23 16:59:25 +08003327 restartCauseIface->initialize();
Jason M. Bills7d4aaac2019-09-19 14:03:44 -07003328
Lei YU92caa4c2021-02-23 16:59:25 +08003329 currentHostStateMonitor();
Yong Li8d660212019-12-27 10:18:10 +08003330
Lei YU92caa4c2021-02-23 16:59:25 +08003331 io.run();
Ed Tanousf61ca6f2019-08-15 15:09:05 -07003332
3333 return 0;
3334}