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