Add fan profile host support
Implement the fan profile portions of get / set fan
profile ipmi commands. These commands have been overused
with too much debug information, currently we only plan
to support the part that the host needs.
Tested-by: Modified the settings on the host and they
were persisted correctly on the next boot
Change-Id: I5736703123154193b8e193ccb14fc2ffb9f5320b
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/CMakeLists.txt.in b/CMakeLists.txt.in
index 811ad43..f7161ac 100644
--- a/CMakeLists.txt.in
+++ b/CMakeLists.txt.in
@@ -9,7 +9,7 @@
externalproject_add (
sdbusplus-project PREFIX ${CMAKE_BINARY_DIR}/sdbusplus-project
GIT_REPOSITORY https://github.com/openbmc/sdbusplus.git GIT_TAG
- 6b4fb2969cd0c853ff6aa7f9bdd3ddaa0081c204 SOURCE_DIR
+ f0dd3b5a3c6c54b4f38844b573e3f157f8064088 SOURCE_DIR
${CMAKE_BINARY_DIR}/sdbusplus-src BINARY_DIR
${CMAKE_BINARY_DIR}/sdbusplus-build CONFIGURE_COMMAND "" BUILD_COMMAND cd
${CMAKE_BINARY_DIR}/sdbusplus-src && ./bootstrap.sh clean && ./bootstrap.sh
@@ -22,7 +22,7 @@
dbus-interfaces PREFIX ${CMAKE_BINARY_DIR}/phosphor-dbus-interfaces DEPENDS
sdbusplus-project GIT_REPOSITORY
https://github.com/openbmc/phosphor-dbus-interfaces GIT_TAG
- 4132f4b6b1de57a993af9bd2bcd039957786a227 SOURCE_DIR
+ 05207d69427cc5f016f08dde801b702d1461cfec SOURCE_DIR
${CMAKE_BINARY_DIR}/phosphor-dbus-interfaces-src BINARY_DIR
${CMAKE_BINARY_DIR}/phosphor-dbus-interfaces-build CONFIGURE_COMMAND ""
BUILD_COMMAND cd ${CMAKE_BINARY_DIR}/phosphor-dbus-interfaces-src && echo
@@ -52,7 +52,7 @@
phosphor-logging PREFIX ${CMAKE_BINARY_DIR}/phosphor-logging DEPENDS cereal
sdbusplus-project dbus-interfaces GIT_REPOSITORY
https://github.com/openbmc/phosphor-logging GIT_TAG
- 477b731ad0fd8c116ffcaa8265a508c9fb112479 SOURCE_DIR
+ 8024d1dc7dfff6360f3e1bdbce145652eb5698be SOURCE_DIR
${CMAKE_BINARY_DIR}/phosphor-logging-src BINARY_DIR
${CMAKE_BINARY_DIR}/phosphor-logging-build CONFIGURE_COMMAND ""
BUILD_COMMAND cd ${CMAKE_BINARY_DIR}/phosphor-logging-src && echo
diff --git a/include/oemcommands.hpp b/include/oemcommands.hpp
index a348db2..df6b007 100644
--- a/include/oemcommands.hpp
+++ b/include/oemcommands.hpp
@@ -26,6 +26,8 @@
cmdGetPowerRestoreDelay = 0x55,
cmdSetShutdownPolicy = 0x60,
cmdGetShutdownPolicy = 0x62,
+ cmdSetFanConfig = 0x89,
+ cmdGetFanConfig = 0x8a,
cmdGetChassisIdentifier = 0x92,
cmdGetProcessorErrConfig = 0x9A,
cmdSetProcessorErrConfig = 0x9B,
@@ -127,6 +129,8 @@
static constexpr const char* fwSetEnvCmd = "/sbin/fw_setenv";
static constexpr const char* fwHostSerailCfgEnvName = "hostserialcfg";
+constexpr const char* settingsBusName = "xyz.openbmc_project.Settings";
+
static constexpr const uint8_t getHostSerialCfgCmd = 0;
static constexpr const uint8_t setHostSerialCfgCmd = 1;
@@ -264,9 +268,34 @@
uint8_t policySupport;
};
+struct SetFanConfigReq
+{
+ uint8_t selectedProfile;
+ uint8_t flags;
+ // other parameters from previous generation are not supported
+};
+
+struct GetFanConfigResp
+{
+ uint8_t supportMask;
+ uint8_t profileSupport;
+ uint8_t fanControlProfileEnable;
+ uint8_t flags;
+ uint8_t dimmPresenceMap[4];
+};
+
struct CfgHostSerialReq
{
uint8_t command;
uint8_t parameter;
};
#pragma pack(pop)
+
+enum class setFanProfileFlags : uint8_t
+{
+ setFanProfile = 7,
+ setPerfAcousMode = 6,
+ // reserved [5:3]
+ performAcousSelect = 2
+ // reserved [1:0]
+};
\ No newline at end of file
diff --git a/src/oemcommands.cpp b/src/oemcommands.cpp
index 5791b28..cc4a437 100644
--- a/src/oemcommands.cpp
+++ b/src/oemcommands.cpp
@@ -20,6 +20,7 @@
#include <ipmid/api.h>
#include <array>
+#include <boost/container/flat_map.hpp>
#include <boost/process/child.hpp>
#include <boost/process/io.hpp>
#include <commandutils.hpp>
@@ -29,6 +30,7 @@
#include <phosphor-logging/log.hpp>
#include <sdbusplus/bus.hpp>
#include <string>
+#include <variant>
#include <vector>
namespace ipmi
@@ -704,6 +706,146 @@
return IPMI_CC_OK;
}
+constexpr const char* thermalModeInterface =
+ "xyz.openbmc_project.Control.ThermalMode";
+constexpr const char* thermalModePath =
+ "/xyz/openbmc_project/control/thermal_mode";
+
+bool getFanProfileInterface(
+ sdbusplus::bus::bus& bus,
+ boost::container::flat_map<
+ std::string, std::variant<std::vector<std::string>, std::string>>& resp)
+{
+ auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
+ "GetAll");
+ call.append(thermalModeInterface);
+ try
+ {
+ auto data = bus.call(call);
+ data.read(resp);
+ }
+ catch (sdbusplus::exception_t& e)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "getFanProfileInterface: can't get thermal mode!",
+ phosphor::logging::entry("ERR=%s", e.what()));
+ return false;
+ }
+ return true;
+}
+
+ipmi_ret_t ipmiOEMSetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t dataLen, ipmi_context_t context)
+{
+
+ if (*dataLen < 2 || *dataLen > 7)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "ipmiOEMSetFanConfig: invalid input len!");
+ *dataLen = 0;
+ return IPMI_CC_REQ_DATA_LEN_INVALID;
+ }
+
+ // todo: tell bios to only send first 2 bytes
+
+ SetFanConfigReq* req = reinterpret_cast<SetFanConfigReq*>(request);
+ boost::container::flat_map<
+ std::string, std::variant<std::vector<std::string>, std::string>>
+ profileData;
+ if (!getFanProfileInterface(dbus, profileData))
+ {
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+
+ std::vector<std::string>* supported =
+ std::get_if<std::vector<std::string>>(&profileData["Supported"]);
+ if (supported == nullptr)
+ {
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+ std::string mode;
+ if (req->flags &
+ (1 << static_cast<uint8_t>(setFanProfileFlags::setPerfAcousMode)))
+ {
+ bool performanceMode =
+ (req->flags & (1 << static_cast<uint8_t>(
+ setFanProfileFlags::performAcousSelect))) > 0;
+
+ if (performanceMode)
+ {
+
+ if (std::find(supported->begin(), supported->end(),
+ "Performance") != supported->end())
+ {
+ mode = "Performance";
+ }
+ }
+ else
+ {
+
+ if (std::find(supported->begin(), supported->end(), "Acoustic") !=
+ supported->end())
+ {
+ mode = "Acoustic";
+ }
+ }
+ if (mode.empty())
+ {
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+ setDbusProperty(dbus, settingsBusName, thermalModePath,
+ thermalModeInterface, "Current", mode);
+ }
+
+ return IPMI_CC_OK;
+}
+
+ipmi_ret_t ipmiOEMGetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t dataLen, ipmi_context_t context)
+{
+
+ if (*dataLen > 1)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "ipmiOEMGetFanConfig: invalid input len!");
+ *dataLen = 0;
+ return IPMI_CC_REQ_DATA_LEN_INVALID;
+ }
+
+ // todo: talk to bios about needing less information
+
+ GetFanConfigResp* resp = reinterpret_cast<GetFanConfigResp*>(response);
+ *dataLen = sizeof(GetFanConfigResp);
+
+ boost::container::flat_map<
+ std::string, std::variant<std::vector<std::string>, std::string>>
+ profileData;
+
+ if (!getFanProfileInterface(dbus, profileData))
+ {
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+
+ std::string* current = std::get_if<std::string>(&profileData["Current"]);
+
+ if (current == nullptr)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "ipmiOEMGetFanConfig: can't get current mode!");
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+ bool performance = (*current == "Performance");
+
+ if (performance)
+ {
+ resp->flags |= 1 << 2;
+ }
+
+ return IPMI_CC_OK;
+}
+
static void registerOEMFunctions(void)
{
phosphor::logging::log<phosphor::logging::level::INFO>(
@@ -766,6 +908,17 @@
static_cast<ipmi_cmd_t>(
IPMINetfnIntelOEMGeneralCmd::cmdGetShutdownPolicy),
NULL, ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
+
+ ipmiPrintAndRegister(
+ netfnIntcOEMGeneral,
+ static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetFanConfig),
+ NULL, ipmiOEMSetFanConfig, PRIVILEGE_USER);
+
+ ipmiPrintAndRegister(
+ netfnIntcOEMGeneral,
+ static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetFanConfig),
+ NULL, ipmiOEMGetFanConfig, PRIVILEGE_USER);
+
ipmiPrintAndRegister(
netfnIntcOEMGeneral,
static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetLEDStatus),
diff --git a/src/utils.cpp b/src/utils.cpp
index 8dac5ab..7619186 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -1,9 +1,8 @@
-#include "phosphor-ipmi-host/utils.hpp"
-
#include <arpa/inet.h>
#include <dirent.h>
#include <net/if.h>
+#include <phosphor-ipmi-host/utils.hpp>
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/log.hpp>
#include <xyz/openbmc_project/Common/error.hpp>