summaryrefslogtreecommitdiffstats
path: root/apphandler.cpp
diff options
context:
space:
mode:
authorYong Li <yong.b.li@linux.intel.com>2018-10-09 01:59:45 +0800
committerVernon Mauery <vernon.mauery@linux.intel.com>2018-11-20 00:34:15 +0000
commit18d772634afe5656ea10263466afe770bfb339b6 (patch)
tree32d1193ca8b0363913e7bb7b0164b9b2cf04c45d /apphandler.cpp
parent46590a3a955493e97fa83e040e9d1f9a0c6faa2c (diff)
downloadphosphor-host-ipmid-18d772634afe5656ea10263466afe770bfb339b6.tar.gz
phosphor-host-ipmid-18d772634afe5656ea10263466afe770bfb339b6.zip
Implement IPMI ACPI set/get commands
The IPMI ACPI set/get power state commands are provided to allow system software to tell a controller the present ACPI power state of the system. This is an independent setting that may not necessarily match the actual power state of the system. The commands are used to enable the reporting of the power state, it does not control or change the power state. The ACPI status will be saved into flash by settings manager. Tested By: Set ACPI: ipmitool -H <IP> -P 0penBmc -I lanplus raw 0x06 0x06 0x86 0x83 Get ACPI: ipmitool -H <IP> -P 0penBmc -I lanplus raw 0x06 0x07 Change-Id: I6d00c0aec931b98d6691d7c4a54698e08d317aa4 Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
Diffstat (limited to 'apphandler.cpp')
-rw-r--r--apphandler.cpp264
1 files changed, 263 insertions, 1 deletions
diff --git a/apphandler.cpp b/apphandler.cpp
index ac06f50..370e0c3 100644
--- a/apphandler.cpp
+++ b/apphandler.cpp
@@ -29,6 +29,7 @@
#include <tuple>
#include <vector>
#include <xyz/openbmc_project/Common/error.hpp>
+#include <xyz/openbmc_project/Control/Power/ACPIPowerState/server.hpp>
#include <xyz/openbmc_project/Software/Activation/server.hpp>
#include <xyz/openbmc_project/Software/Version/server.hpp>
#include <xyz/openbmc_project/State/BMC/server.hpp>
@@ -179,16 +180,273 @@ bool getCurrentBmcState()
variant_ns::get<std::string>(variant)) == BMC::BMCState::Ready;
}
+namespace acpi_state
+{
+using namespace sdbusplus::xyz::openbmc_project::Control::Power::server;
+
+const static constexpr char* acpiObjPath =
+ "/xyz/openbmc_project/control/host0/acpi_power_state";
+const static constexpr char* acpiInterface =
+ "xyz.openbmc_project.Control.Power.ACPIPowerState";
+const static constexpr char* sysACPIProp = "SysACPIStatus";
+const static constexpr char* devACPIProp = "DevACPIStatus";
+
+enum class PowerStateType : uint8_t
+{
+ sysPowerState = 0x00,
+ devPowerState = 0x01,
+};
+
+// Defined in 20.6 of ipmi doc
+enum class PowerState : uint8_t
+{
+ s0G0D0 = 0x00,
+ s1D1 = 0x01,
+ s2D2 = 0x02,
+ s3D3 = 0x03,
+ s4 = 0x04,
+ s5G2 = 0x05,
+ s4S5 = 0x06,
+ g3 = 0x07,
+ sleep = 0x08,
+ g1Sleep = 0x09,
+ override = 0x0a,
+ legacyOn = 0x20,
+ legacyOff = 0x21,
+ unknown = 0x2a,
+ noChange = 0x7f,
+};
+
+static constexpr uint8_t stateChanged = 0x80;
+
+struct ACPIState
+{
+ uint8_t sysACPIState;
+ uint8_t devACPIState;
+} __attribute__((packed));
+
+std::map<ACPIPowerState::ACPI, PowerState> dbusToIPMI = {
+ {ACPIPowerState::ACPI::S0_G0_D0, PowerState::s0G0D0},
+ {ACPIPowerState::ACPI::S1_D1, PowerState::s1D1},
+ {ACPIPowerState::ACPI::S2_D2, PowerState::s2D2},
+ {ACPIPowerState::ACPI::S3_D3, PowerState::s3D3},
+ {ACPIPowerState::ACPI::S4, PowerState::s4},
+ {ACPIPowerState::ACPI::S5_G2, PowerState::s5G2},
+ {ACPIPowerState::ACPI::S4_S5, PowerState::s4S5},
+ {ACPIPowerState::ACPI::G3, PowerState::g3},
+ {ACPIPowerState::ACPI::SLEEP, PowerState::sleep},
+ {ACPIPowerState::ACPI::G1_SLEEP, PowerState::g1Sleep},
+ {ACPIPowerState::ACPI::OVERRIDE, PowerState::override},
+ {ACPIPowerState::ACPI::LEGACY_ON, PowerState::legacyOn},
+ {ACPIPowerState::ACPI::LEGACY_OFF, PowerState::legacyOff},
+ {ACPIPowerState::ACPI::Unknown, PowerState::unknown}};
+
+bool isValidACPIState(acpi_state::PowerStateType type, uint8_t state)
+{
+ if (type == acpi_state::PowerStateType::sysPowerState)
+ {
+ if ((state <= static_cast<uint8_t>(acpi_state::PowerState::override)) ||
+ (state == static_cast<uint8_t>(acpi_state::PowerState::legacyOn)) ||
+ (state ==
+ static_cast<uint8_t>(acpi_state::PowerState::legacyOff)) ||
+ (state == static_cast<uint8_t>(acpi_state::PowerState::unknown)) ||
+ (state == static_cast<uint8_t>(acpi_state::PowerState::noChange)))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if (type == acpi_state::PowerStateType::devPowerState)
+ {
+ if ((state <= static_cast<uint8_t>(acpi_state::PowerState::s3D3)) ||
+ (state == static_cast<uint8_t>(acpi_state::PowerState::unknown)) ||
+ (state == static_cast<uint8_t>(acpi_state::PowerState::noChange)))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ return false;
+}
+} // namespace acpi_state
+
ipmi_ret_t ipmi_app_set_acpi_power_state(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
ipmi_request_t request,
ipmi_response_t response,
ipmi_data_len_t data_len,
ipmi_context_t context)
{
+ auto s = static_cast<uint8_t>(acpi_state::PowerState::unknown);
ipmi_ret_t rc = IPMI_CC_OK;
+
+ sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
+
+ auto value = acpi_state::ACPIPowerState::ACPI::Unknown;
+
+ auto* req = reinterpret_cast<acpi_state::ACPIState*>(request);
+
+ if (*data_len != sizeof(acpi_state::ACPIState))
+ {
+ log<level::ERR>("set_acpi invalid len");
+ *data_len = 0;
+ return IPMI_CC_REQ_DATA_LEN_INVALID;
+ }
+
*data_len = 0;
- log<level::DEBUG>("IPMI SET ACPI STATE Ignoring for now\n");
+ if (req->sysACPIState & acpi_state::stateChanged)
+ {
+ // set system power state
+ s = req->sysACPIState & ~acpi_state::stateChanged;
+
+ if (!acpi_state::isValidACPIState(
+ acpi_state::PowerStateType::sysPowerState, s))
+ {
+ log<level::ERR>("set_acpi_power sys invalid input",
+ entry("S=%x", s));
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+ }
+
+ // valid input
+ if (s == static_cast<uint8_t>(acpi_state::PowerState::noChange))
+ {
+ log<level::DEBUG>("No change for system power state");
+ }
+ else
+ {
+ auto found = std::find_if(
+ acpi_state::dbusToIPMI.begin(), acpi_state::dbusToIPMI.end(),
+ [&s](const auto& iter) {
+ return (static_cast<uint8_t>(iter.second) == s);
+ });
+
+ value = found->first;
+
+ try
+ {
+ auto acpiObject =
+ ipmi::getDbusObject(bus, acpi_state::acpiInterface);
+ ipmi::setDbusProperty(bus, acpiObject.second, acpiObject.first,
+ acpi_state::acpiInterface,
+ acpi_state::sysACPIProp,
+ convertForMessage(value));
+ }
+ catch (const InternalFailure& e)
+ {
+ log<level::ERR>("Failed in set ACPI system property",
+ entry("EXCEPTION=%s", e.what()));
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+ }
+ }
+ else
+ {
+ log<level::DEBUG>("Do not change system power state");
+ }
+
+ if (req->devACPIState & acpi_state::stateChanged)
+ {
+ // set device power state
+ s = req->devACPIState & ~acpi_state::stateChanged;
+ if (!acpi_state::isValidACPIState(
+ acpi_state::PowerStateType::devPowerState, s))
+ {
+ log<level::ERR>("set_acpi_power dev invalid input",
+ entry("S=%x", s));
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+ }
+
+ // valid input
+ if (s == static_cast<uint8_t>(acpi_state::PowerState::noChange))
+ {
+ log<level::DEBUG>("No change for device power state");
+ }
+ else
+ {
+ auto found = std::find_if(
+ acpi_state::dbusToIPMI.begin(), acpi_state::dbusToIPMI.end(),
+ [&s](const auto& iter) {
+ return (static_cast<uint8_t>(iter.second) == s);
+ });
+
+ value = found->first;
+
+ try
+ {
+ auto acpiObject =
+ ipmi::getDbusObject(bus, acpi_state::acpiInterface);
+ ipmi::setDbusProperty(bus, acpiObject.second, acpiObject.first,
+ acpi_state::acpiInterface,
+ acpi_state::devACPIProp,
+ convertForMessage(value));
+ }
+ catch (const InternalFailure& e)
+ {
+ log<level::ERR>("Failed in set ACPI device property",
+ entry("EXCEPTION=%s", e.what()));
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+ }
+ }
+ else
+ {
+ log<level::DEBUG>("Do not change device power state");
+ }
+
+ return rc;
+}
+
+ipmi_ret_t ipmi_app_get_acpi_power_state(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request,
+ ipmi_response_t response,
+ ipmi_data_len_t data_len,
+ ipmi_context_t context)
+{
+ ipmi_ret_t rc = IPMI_CC_OK;
+
+ auto* res = reinterpret_cast<acpi_state::ACPIState*>(response);
+
+ sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
+
+ *data_len = 0;
+
+ try
+ {
+ auto acpiObject = ipmi::getDbusObject(bus, acpi_state::acpiInterface);
+
+ auto sysACPIVal = ipmi::getDbusProperty(
+ bus, acpiObject.second, acpiObject.first, acpi_state::acpiInterface,
+ acpi_state::sysACPIProp);
+ auto sysACPI = acpi_state::ACPIPowerState::convertACPIFromString(
+ sysACPIVal.get<std::string>());
+ res->sysACPIState =
+ static_cast<uint8_t>(acpi_state::dbusToIPMI.at(sysACPI));
+
+ auto devACPIVal = ipmi::getDbusProperty(
+ bus, acpiObject.second, acpiObject.first, acpi_state::acpiInterface,
+ acpi_state::devACPIProp);
+ auto devACPI = acpi_state::ACPIPowerState::convertACPIFromString(
+ devACPIVal.get<std::string>());
+ res->devACPIState =
+ static_cast<uint8_t>(acpi_state::dbusToIPMI.at(devACPI));
+
+ *data_len = sizeof(acpi_state::ACPIState);
+ }
+ catch (const InternalFailure& e)
+ {
+ log<level::ERR>("Failed in get ACPI property");
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
return rc;
}
@@ -860,6 +1118,10 @@ void register_netfn_app_functions()
ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_ACPI, NULL,
ipmi_app_set_acpi_power_state, PRIVILEGE_ADMIN);
+ // <Get ACPI Power State>
+ ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_ACPI, NULL,
+ ipmi_app_get_acpi_power_state, PRIVILEGE_ADMIN);
+
// <Get Channel Access>
ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_ACCESS, NULL,
ipmi_get_channel_access, PRIVILEGE_USER);
OpenPOWER on IntegriCloud