xref: /openbmc/google-misc/ncsid/subprojects/bare-metal-host-monitor/host_gpio_monitor.cpp (revision c9a43a3017d248aa821792899f29d408a7ca4c26)
1dd9478ddSJohn Wedig 
2376d781cSJohn Wedig #include "absl/flags/flag.h"
3376d781cSJohn Wedig #include "absl/flags/parse.h"
4376d781cSJohn Wedig 
5815c8873SJohn Wedig #include "host_gpio_monitor_conf.hpp"
6815c8873SJohn Wedig 
7*c9a43a30SJohn Wedig #include <systemd/sd-daemon.h>
8*c9a43a30SJohn Wedig 
9dd9478ddSJohn Wedig #include <boost/asio/io_context.hpp>
10dd9478ddSJohn Wedig #include <boost/asio/steady_timer.hpp>
11dd9478ddSJohn Wedig #include <phosphor-logging/lg2.hpp>
12dd9478ddSJohn Wedig #include <sdbusplus/asio/connection.hpp>
13dd9478ddSJohn Wedig #include <sdbusplus/asio/property.hpp>
14dd9478ddSJohn Wedig #include <sdbusplus/bus.hpp>
15dd9478ddSJohn Wedig #include <sdbusplus/bus/match.hpp>
16dd9478ddSJohn Wedig 
17376d781cSJohn Wedig #include <format>
18376d781cSJohn Wedig 
19376d781cSJohn Wedig ABSL_FLAG(std::string, host_label, "0",
20376d781cSJohn Wedig           "Label for the host in question. Usually this is an integer.");
21376d781cSJohn Wedig 
22dd9478ddSJohn Wedig const constexpr char* OperatingSystemStateInactive =
23dd9478ddSJohn Wedig     "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive";
24376d781cSJohn Wedig const constexpr char* BareMetalActiveTargetTemplate =
25376d781cSJohn Wedig     "gbmc-bare-metal-active@{}.target";
26dd9478ddSJohn Wedig 
27dd9478ddSJohn Wedig const constexpr char* SystemdService = "org.freedesktop.systemd1";
28dd9478ddSJohn Wedig const constexpr char* SystemdManagerObject = "/org/freedesktop/systemd1";
29dd9478ddSJohn Wedig const constexpr char* SystemdManagerInterface =
30dd9478ddSJohn Wedig     "org.freedesktop.systemd1.Manager";
31dd9478ddSJohn Wedig 
32376d781cSJohn Wedig void setUnitStatus(sdbusplus::asio::connection& bus, bool status,
33376d781cSJohn Wedig                    const std::string& host_instance)
34dd9478ddSJohn Wedig {
35dd9478ddSJohn Wedig     auto method = bus.new_method_call(SystemdService, SystemdManagerObject,
36dd9478ddSJohn Wedig                                       SystemdManagerInterface,
37dd9478ddSJohn Wedig                                       status ? "StartUnit" : "StopUnit");
38376d781cSJohn Wedig     method.append(std::format(BareMetalActiveTargetTemplate, host_instance),
39376d781cSJohn Wedig                   "replace");
40dd9478ddSJohn Wedig 
41dd9478ddSJohn Wedig     bus.call(method);
42dd9478ddSJohn Wedig }
43dd9478ddSJohn Wedig 
44dd9478ddSJohn Wedig void checkPostComplete(sdbusplus::asio::connection& bus,
45376d781cSJohn Wedig                        const std::string& state, bool action,
46376d781cSJohn Wedig                        const std::string& host_instance)
47dd9478ddSJohn Wedig {
48dd9478ddSJohn Wedig     sdbusplus::asio::getProperty<std::string>(
49815c8873SJohn Wedig         bus, std::format(DBUS_SERVICE_NAME, host_instance),
50815c8873SJohn Wedig         std::format(DBUS_OBJECT_PATH, host_instance), DBUS_INTERFACE,
51815c8873SJohn Wedig         DBUS_PROPERTY_NAME,
528800984dSYuxiao Zhang         [&, state, action](const boost::system::error_code& ec,
53dd9478ddSJohn Wedig                            const std::string& postCompleteState) {
54dd9478ddSJohn Wedig             if (ec)
55dd9478ddSJohn Wedig             {
56dd9478ddSJohn Wedig                 lg2::error("Error when checking Post Complete GPIO state");
57dd9478ddSJohn Wedig                 return;
58dd9478ddSJohn Wedig             }
59dd9478ddSJohn Wedig 
60c66ebc35SPatrick Williams             lg2::info("Post Complete state is {STATE}", "STATE",
61c66ebc35SPatrick Williams                       postCompleteState);
628800984dSYuxiao Zhang 
63dd9478ddSJohn Wedig             /*
64815c8873SJohn Wedig              * If the host OS is running (e.g. OperatingSystemState is Standby),
65815c8873SJohn Wedig              * enable the bare-metal-active systemd target.
66815c8873SJohn Wedig              * If the host CPU is in reset (e.g. OperatingSystemState is
67815c8873SJohn Wedig              * Inactive), no-op cause IPMI is enabled by default.
68dd9478ddSJohn Wedig              */
69dd9478ddSJohn Wedig             if (postCompleteState == state)
70dd9478ddSJohn Wedig             {
71376d781cSJohn Wedig                 setUnitStatus(bus, action, host_instance);
72dd9478ddSJohn Wedig             }
73dd9478ddSJohn Wedig         });
74dd9478ddSJohn Wedig }
75dd9478ddSJohn Wedig 
76dd9478ddSJohn Wedig /* This only gets called once on startup. */
77376d781cSJohn Wedig void checkPostCompleteStartup(sdbusplus::asio::connection& bus,
78376d781cSJohn Wedig                               const std::string& host_instance)
79dd9478ddSJohn Wedig {
80815c8873SJohn Wedig     checkPostComplete(bus, DBUS_PROPERTY_HOST_RUNNING_VALUE, true,
81815c8873SJohn Wedig                       host_instance);
82dd9478ddSJohn Wedig }
83dd9478ddSJohn Wedig 
84dd9478ddSJohn Wedig /* Gets called when a GPIO state change is detected. */
85376d781cSJohn Wedig void checkPostCompleteEvent(sdbusplus::asio::connection& bus,
86376d781cSJohn Wedig                             const std::string& host_instance)
87dd9478ddSJohn Wedig {
88815c8873SJohn Wedig     checkPostComplete(bus, DBUS_PROPERTY_HOST_IN_RESET_VALUE, false,
89815c8873SJohn Wedig                       host_instance);
90dd9478ddSJohn Wedig }
91dd9478ddSJohn Wedig 
92376d781cSJohn Wedig int main(int argc, char** argv)
93dd9478ddSJohn Wedig {
94376d781cSJohn Wedig     absl::ParseCommandLine(argc, argv);
95376d781cSJohn Wedig     std::string host_label = absl::GetFlag(FLAGS_host_label);
96376d781cSJohn Wedig 
97dd9478ddSJohn Wedig     try
98dd9478ddSJohn Wedig     {
99dd9478ddSJohn Wedig         /* Setup connection to dbus. */
100dd9478ddSJohn Wedig         boost::asio::io_context io;
101dd9478ddSJohn Wedig         auto conn = sdbusplus::asio::connection(io);
102dd9478ddSJohn Wedig 
103dd9478ddSJohn Wedig         /* check IPMI status at startup */
104376d781cSJohn Wedig         checkPostCompleteStartup(conn, host_label);
105*c9a43a30SJohn Wedig 
106*c9a43a30SJohn Wedig         /* Notify that the service is done starting up. */
107*c9a43a30SJohn Wedig         sd_notify(0, "READY=1");
108*c9a43a30SJohn Wedig 
109dd9478ddSJohn Wedig         /*
110dd9478ddSJohn Wedig          * Set up an event handler to process Post Complete GPIO state changes.
111dd9478ddSJohn Wedig          */
112dd9478ddSJohn Wedig         boost::asio::steady_timer filterTimer(io);
113dd9478ddSJohn Wedig 
114815c8873SJohn Wedig         /*
115815c8873SJohn Wedig          * Prepare object path we want to monitor, substituting in the host
116815c8873SJohn Wedig          * label, if needed.
117815c8873SJohn Wedig          */
118815c8873SJohn Wedig         std::string objectPath = std::format(DBUS_OBJECT_PATH, host_label);
119815c8873SJohn Wedig 
120dd9478ddSJohn Wedig         auto match = std::make_unique<sdbusplus::bus::match_t>(
121dd9478ddSJohn Wedig             static_cast<sdbusplus::bus_t&>(conn),
122dd9478ddSJohn Wedig             std::format(
123dd9478ddSJohn Wedig                 "type='signal',member='PropertiesChanged',path_namespace='"
124815c8873SJohn Wedig                 "{}',arg0namespace='{}'",
125815c8873SJohn Wedig                 objectPath, DBUS_INTERFACE),
126dd9478ddSJohn Wedig             [&](sdbusplus::message_t& message) {
127dd9478ddSJohn Wedig                 if (message.is_method_error())
128dd9478ddSJohn Wedig                 {
129dd9478ddSJohn Wedig                     lg2::error("eventHandler callback method error");
130dd9478ddSJohn Wedig                     return;
131dd9478ddSJohn Wedig                 }
132dd9478ddSJohn Wedig 
133dd9478ddSJohn Wedig                 /*
134dd9478ddSJohn Wedig                  * This implicitly cancels the timer, if it's already pending.
135dd9478ddSJohn Wedig                  * If there's a burst of events within a short period, we want
136dd9478ddSJohn Wedig                  * to handle them all at once. So, we will wait this long for no
137dd9478ddSJohn Wedig                  * more events to occur, before processing them.
138dd9478ddSJohn Wedig                  */
1393aed6961SJohn Wedig                 filterTimer.expires_from_now(std::chrono::milliseconds(100));
140dd9478ddSJohn Wedig 
141c66ebc35SPatrick Williams                 filterTimer.async_wait(
142c66ebc35SPatrick Williams                     [&](const boost::system::error_code& ec) {
143dd9478ddSJohn Wedig                         if (ec == boost::asio::error::operation_aborted)
144dd9478ddSJohn Wedig                         {
145dd9478ddSJohn Wedig                             /* we were canceled */
146dd9478ddSJohn Wedig                             return;
147dd9478ddSJohn Wedig                         }
148dd9478ddSJohn Wedig                         if (ec)
149dd9478ddSJohn Wedig                         {
150dd9478ddSJohn Wedig                             lg2::error("timer error");
151dd9478ddSJohn Wedig                             return;
152dd9478ddSJohn Wedig                         }
153dd9478ddSJohn Wedig 
154dd9478ddSJohn Wedig                         /*
155c66ebc35SPatrick Williams                          * Stop the bare metal active target if the post
156c66ebc35SPatrick Williams                          * complete got deasserted.
157dd9478ddSJohn Wedig                          */
158376d781cSJohn Wedig                         checkPostCompleteEvent(conn, host_label);
159dd9478ddSJohn Wedig                     });
160dd9478ddSJohn Wedig             });
161dd9478ddSJohn Wedig 
162dd9478ddSJohn Wedig         io.run();
163dd9478ddSJohn Wedig         return 0;
164dd9478ddSJohn Wedig     }
165dd9478ddSJohn Wedig     catch (const std::exception& e)
166dd9478ddSJohn Wedig     {
167dd9478ddSJohn Wedig         lg2::error(e.what(), "REDFISH_MESSAGE_ID",
168dd9478ddSJohn Wedig                    std::string("OpenBMC.1.0.ServiceException"));
169dd9478ddSJohn Wedig 
170dd9478ddSJohn Wedig         return 2;
171dd9478ddSJohn Wedig     }
172dd9478ddSJohn Wedig     return 1;
173dd9478ddSJohn Wedig }
174