Add Get / Set Dimm offset ipmi commands
Implement the commands, store data in json. Also push
setting to d-bus for dimm offset for dimms to use
to modify thresholds.
Tested:
set offsets using set command and data returned by
get was correct
Change-Id: I5ab2604ce11f5ecf49b01e352ce8c15be8eefb72
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/include/oemcommands.hpp b/include/oemcommands.hpp
index f4f228f..fa23a98 100644
--- a/include/oemcommands.hpp
+++ b/include/oemcommands.hpp
@@ -35,6 +35,8 @@
cmdGetFanConfig = 0x8a,
cmdSetFanSpeedOffset = 0x8c,
cmdGetFanSpeedOffset = 0x8d,
+ cmdSetDimmOffset = 0x8e,
+ cmdGetDimmOffset = 0x8f,
cmdSetFscParameter = 0x90,
cmdGetFscParameter = 0x91,
cmdGetChassisIdentifier = 0x92,
@@ -326,6 +328,12 @@
cfm = 0x4
};
+enum class dimmOffsetTypes : uint8_t
+{
+ staticCltt = 0x0,
+ dimmPower = 0x2
+};
+
// FIXME: this stuff needs to be rewritten
enum IPMI_INTEL_OEM_RETURN_CODES
{
diff --git a/src/oemcommands.cpp b/src/oemcommands.cpp
index b612948..5edc82a 100644
--- a/src/oemcommands.cpp
+++ b/src/oemcommands.cpp
@@ -30,6 +30,7 @@
#include <iostream>
#include <ipmid/api.hpp>
#include <ipmid/utils.hpp>
+#include <nlohmann/json.hpp>
#include <oemcommands.hpp>
#include <phosphor-logging/log.hpp>
#include <sdbusplus/bus.hpp>
@@ -62,6 +63,8 @@
static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource";
static constexpr const char* oemNmiEnabledObjPathProp = "Enabled";
+static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json";
+
enum class NmiSource : uint8_t
{
none = 0,
@@ -2116,6 +2119,146 @@
return ipmi::responseSuccess();
}
+namespace dimmOffset
+{
+constexpr const char* dimmPower = "DimmPower";
+constexpr const char* staticCltt = "StaticCltt";
+constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
+constexpr const char* offsetInterface =
+ "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
+constexpr const char* property = "DimmOffset";
+
+}; // namespace dimmOffset
+
+ipmi::RspType<>
+ ipmiOEMSetDimmOffset(uint8_t type,
+ const std::vector<std::tuple<uint8_t, uint8_t>>& data)
+{
+ if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
+ type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
+ {
+ return ipmi::responseInvalidFieldRequest();
+ }
+
+ if (data.empty())
+ {
+ return ipmi::responseInvalidFieldRequest();
+ }
+ nlohmann::json json;
+
+ std::ifstream jsonStream(dimmOffsetFile);
+ if (jsonStream.good())
+ {
+ json = nlohmann::json::parse(jsonStream, nullptr, false);
+ if (json.is_discarded())
+ {
+ json = nlohmann::json();
+ }
+ jsonStream.close();
+ }
+
+ std::string typeName;
+ if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
+ {
+ typeName = dimmOffset::dimmPower;
+ }
+ else
+ {
+ typeName = dimmOffset::staticCltt;
+ }
+
+ nlohmann::json& field = json[typeName];
+
+ for (const auto& [index, value] : data)
+ {
+ field[index] = value;
+ }
+
+ for (nlohmann::json& val : field)
+ {
+ if (val == nullptr)
+ {
+ val = static_cast<uint8_t>(0);
+ }
+ }
+
+ std::ofstream output(dimmOffsetFile);
+ if (!output.good())
+ {
+ std::cerr << "Error writing json file\n";
+ return ipmi::responseResponseError();
+ }
+
+ output << json.dump(4);
+
+ if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
+ {
+ std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
+
+ std::variant<std::vector<uint8_t>> offsets =
+ field.get<std::vector<uint8_t>>();
+ auto call = bus->new_method_call(
+ settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
+ call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
+ try
+ {
+ bus->call(call);
+ }
+ catch (sdbusplus::exception_t& e)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "ipmiOEMSetDimmOffset: can't set dimm offsets!",
+ phosphor::logging::entry("ERR=%s", e.what()));
+ return ipmi::responseResponseError();
+ }
+ }
+
+ return ipmi::responseSuccess();
+}
+
+ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
+{
+
+ if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
+ type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
+ {
+ return ipmi::responseInvalidFieldRequest();
+ }
+
+ std::ifstream jsonStream(dimmOffsetFile);
+
+ auto json = nlohmann::json::parse(jsonStream, nullptr, false);
+ if (json.is_discarded())
+ {
+ std::cerr << "File error in " << dimmOffsetFile << "\n";
+ return ipmi::responseResponseError();
+ }
+
+ std::string typeName;
+ if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
+ {
+ typeName = dimmOffset::dimmPower;
+ }
+ else
+ {
+ typeName = dimmOffset::staticCltt;
+ }
+
+ auto it = json.find(typeName);
+ if (it == json.end())
+ {
+ return ipmi::responseInvalidFieldRequest();
+ }
+
+ if (it->size() <= index)
+ {
+ return ipmi::responseInvalidFieldRequest();
+ }
+
+ uint8_t resp = it->at(index).get<uint8_t>();
+ return ipmi::responseSuccess(resp);
+}
+
static void registerOEMFunctions(void)
{
phosphor::logging::log<phosphor::logging::level::INFO>(
@@ -2268,6 +2411,16 @@
registerHandler(prioOemBase, netfn::intel::oemGeneral,
netfn::intel::cmdRestoreConfiguration, Privilege::Admin,
ipmiRestoreConfiguration);
+
+ ipmi::registerHandler(
+ ipmi::prioOemBase, netfnIntcOEMGeneral,
+ static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetDimmOffset),
+ ipmi::Privilege::Operator, ipmiOEMSetDimmOffset);
+
+ ipmi::registerHandler(
+ ipmi::prioOemBase, netfnIntcOEMGeneral,
+ static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetDimmOffset),
+ ipmi::Privilege::Operator, ipmiOEMGetDimmOffset);
}
} // namespace ipmi