blob: 889ab93c5c2d9886381ff86acbd97b2e5d971711 [file] [log] [blame]
John Wedigdd9478d2023-12-08 14:44:53 -08001
2#include <boost/asio/io_context.hpp>
3#include <boost/asio/steady_timer.hpp>
4#include <phosphor-logging/lg2.hpp>
5#include <sdbusplus/asio/connection.hpp>
6#include <sdbusplus/asio/property.hpp>
7#include <sdbusplus/bus.hpp>
8#include <sdbusplus/bus/match.hpp>
9
10const constexpr char* OperatingSystemService =
11 "xyz.openbmc_project.State.OperatingSystem";
12const constexpr char* OperatingSystemPath = "/xyz/openbmc_project/state/os";
13const constexpr char* OperatingSystemStatusInterface =
14 "xyz.openbmc_project.State.OperatingSystem.Status";
15const constexpr char* OperatingSystemStateProperty = "OperatingSystemState";
16const constexpr char* OperatingSystemStateStandby =
17 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Standby";
18const constexpr char* OperatingSystemStateInactive =
19 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
20const constexpr char* BareMetalActiveTarget = "gbmc-bare-metal-active.target";
21
22const constexpr char* SystemdService = "org.freedesktop.systemd1";
23const constexpr char* SystemdManagerObject = "/org/freedesktop/systemd1";
24const constexpr char* SystemdManagerInterface =
25 "org.freedesktop.systemd1.Manager";
26
27void setUnitStatus(sdbusplus::asio::connection& bus, bool status)
28{
29 auto method = bus.new_method_call(SystemdService, SystemdManagerObject,
30 SystemdManagerInterface,
31 status ? "StartUnit" : "StopUnit");
32 method.append(BareMetalActiveTarget, "replace");
33
34 bus.call(method);
35}
36
37/* This only gets called once on startup. */
38void checkPostComplete(sdbusplus::asio::connection& bus,
39 const std::string& state, bool action)
40{
41 sdbusplus::asio::getProperty<std::string>(
42 bus, OperatingSystemService, OperatingSystemPath,
43 OperatingSystemStatusInterface, OperatingSystemStateProperty,
44 [&](const boost::system::error_code& ec,
45 const std::string& postCompleteState) {
46 if (ec)
47 {
48 lg2::error("Error when checking Post Complete GPIO state");
49 return;
50 }
51
52 lg2::info("Post Complete state is {STATE}", "STATE", postCompleteState);
53 /*
54 * If state is Standby, enable the bare-metal-active systemd
55 * target.
56 * If state is Inactive, no-op cause IPMI is enabled by default.
57 */
58 if (postCompleteState == state)
59 {
60 setUnitStatus(bus, action);
61 }
62 });
63}
64
65/* This only gets called once on startup. */
66void checkPostCompleteStartup(sdbusplus::asio::connection& bus)
67{
68 checkPostComplete(bus, OperatingSystemStateStandby, true);
69}
70
71/* Gets called when a GPIO state change is detected. */
72void checkPostCompleteEvent(sdbusplus::asio::connection& bus)
73{
74 checkPostComplete(bus, OperatingSystemStateInactive, false);
75}
76
77int main()
78{
79 try
80 {
81 /* Setup connection to dbus. */
82 boost::asio::io_context io;
83 auto conn = sdbusplus::asio::connection(io);
84
85 /* check IPMI status at startup */
86 checkPostCompleteStartup(conn);
87 /*
88 * Set up an event handler to process Post Complete GPIO state changes.
89 */
90 boost::asio::steady_timer filterTimer(io);
91
92 auto match = std::make_unique<sdbusplus::bus::match_t>(
93 static_cast<sdbusplus::bus_t&>(conn),
94 std::format(
95 "type='signal',member='PropertiesChanged',path_namespace='"
96 "/xyz/openbmc_project/state/os',arg0namespace='{}'",
97 OperatingSystemStatusInterface),
98 [&](sdbusplus::message_t& message) {
99 if (message.is_method_error())
100 {
101 lg2::error("eventHandler callback method error");
102 return;
103 }
104
105 /*
106 * This implicitly cancels the timer, if it's already pending.
107 * If there's a burst of events within a short period, we want
108 * to handle them all at once. So, we will wait this long for no
109 * more events to occur, before processing them.
110 */
111 filterTimer.expires_from_now(std::chrono::seconds(1));
112
113 filterTimer.async_wait([&](const boost::system::error_code& ec) {
114 if (ec == boost::asio::error::operation_aborted)
115 {
116 /* we were canceled */
117 return;
118 }
119 if (ec)
120 {
121 lg2::error("timer error");
122 return;
123 }
124
125 /*
126 * Stop the bare metal active target if the post complete got
127 * deasserted.
128 */
129 checkPostCompleteEvent(conn);
130 });
131 });
132
133 io.run();
134 return 0;
135 }
136 catch (const std::exception& e)
137 {
138 lg2::error(e.what(), "REDFISH_MESSAGE_ID",
139 std::string("OpenBMC.1.0.ServiceException"));
140
141 return 2;
142 }
143 return 1;
144}