Expose memory error correction type
Memory error correction types are provided by smbios table type-16.
This change use that table to populate 'ECC' field in
xyz.openbmc_project.Inventory.Item.Dimm interface.
Tested:
Tested this on a real machine.
Signed-off-by: Kasun Athukorala <kasunath@google.com>
Change-Id: Iaeb27f81d9b97be1858d1c4564318f5dc69cfa4f
diff --git a/include/dimm.hpp b/include/dimm.hpp
index 1d1fc18..709bfdf 100644
--- a/include/dimm.hpp
+++ b/include/dimm.hpp
@@ -34,6 +34,9 @@
using DeviceType =
sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::DeviceType;
+using EccType =
+ sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::Ecc;
+
class Dimm :
sdbusplus::server::object_t<
sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm>,
@@ -105,6 +108,7 @@
uint8_t memoryAttributes(uint8_t value) override;
uint16_t memoryConfiguredSpeedInMhz(uint16_t value) override;
bool functional(bool value) override;
+ EccType ecc(EccType value) override;
private:
uint8_t dimmNum;
@@ -125,6 +129,7 @@
uint8_t* dataIn);
void dimmPartNum(const uint8_t positionNum, const uint8_t structLen,
uint8_t* dataIn);
+ void updateEccType(uint16_t exPhyArrayHandle);
};
struct MemoryInfo
@@ -167,6 +172,25 @@
uint64_t logicalSize;
} __attribute__((packed));
+/**
+ * @brief Struct to represent SMBIOS 3.2 type-16 (Physical Memory Array) data.
+ */
+struct PhysicalMemoryArrayInfo
+{
+ uint8_t type;
+ uint8_t length;
+ uint16_t handle;
+ uint8_t location;
+ uint8_t use;
+ uint8_t memoryErrorCorrection;
+ uint32_t maximumCapacity;
+ uint16_t memoryErrorInformationHandle;
+ uint16_t numberOfMemoryDevices;
+ uint64_t extendedMaximumCapacity;
+} __attribute__((packed));
+static_assert(sizeof(PhysicalMemoryArrayInfo) == 23,
+ "Size of PhysicalMemoryArrayInfo struct is incorrect.");
+
const std::map<uint8_t, DeviceType> dimmTypeTable = {
{0x1, DeviceType::Other}, {0x2, DeviceType::Unknown},
{0x3, DeviceType::DRAM}, {0x4, DeviceType::EDRAM},
@@ -191,6 +215,20 @@
"CMOS", "EDO", "Window DRAM", "Cache DRAM",
"Non-volatile", "Registered", "Unbuffered", "LRDIMM"};
+/**
+ * @brief Map SMBIOS 3.2 Memory Array Error Correction Types to
+ * xyz.openbmc_project.Inventory.Item.Dimm.Ecc types.
+ *
+ * SMBIOS 3.2 Memory Array Error Correction Types 'Unknown', 'None', 'CRC' are
+ * mapped to EccType::NoECC since the DBUs interface does not support those
+ * representations.
+ */
+const std::map<uint8_t, EccType> dimmEccTypeMap = {
+ {0x1, EccType::NoECC}, {0x2, EccType::NoECC},
+ {0x3, EccType::NoECC}, {0x4, EccType::AddressParity},
+ {0x5, EccType::SingleBitECC}, {0x6, EccType::MultiBitECC},
+ {0x7, EccType::NoECC}};
+
} // namespace smbios
} // namespace phosphor
diff --git a/src/dimm.cpp b/src/dimm.cpp
index 1177e66..990b310 100644
--- a/src/dimm.cpp
+++ b/src/dimm.cpp
@@ -19,6 +19,7 @@
#include "mdrv2.hpp"
#include <boost/algorithm/string.hpp>
+#include <phosphor-logging/elog-errors.hpp>
namespace phosphor
{
@@ -28,6 +29,9 @@
using DeviceType =
sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::DeviceType;
+using EccType =
+ sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::Ecc;
+
static constexpr uint16_t maxOldDimmSize = 0x7fff;
void Dimm::memoryInfoUpdate(void)
{
@@ -76,6 +80,8 @@
memoryAttributes(memoryInfo->attributes);
memoryConfiguredSpeedInMhz(memoryInfo->confClockSpeed);
+ updateEccType(memoryInfo->phyArrayHandle);
+
if (!motherboardPath.empty())
{
std::vector<std::tuple<std::string, std::string, std::string>> assocs;
@@ -86,6 +92,49 @@
return;
}
+void Dimm::updateEccType(uint16_t exPhyArrayHandle)
+{
+ uint8_t* dataIn = storage;
+
+ while (dataIn != nullptr)
+ {
+ dataIn = getSMBIOSTypePtr(dataIn, physicalMemoryArrayType);
+ if (dataIn == nullptr)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Failed to get SMBIOS table type-16 data.");
+ return;
+ }
+
+ auto info = reinterpret_cast<struct PhysicalMemoryArrayInfo*>(dataIn);
+ if (info->handle == exPhyArrayHandle)
+ {
+ std::map<uint8_t, EccType>::const_iterator it =
+ dimmEccTypeMap.find(info->memoryErrorCorrection);
+ if (it == dimmEccTypeMap.end())
+ {
+ ecc(EccType::NoECC);
+ }
+ else
+ {
+ ecc(it->second);
+ }
+ return;
+ }
+
+ dataIn = smbiosNextPtr(dataIn);
+ }
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Failed find the corresponding SMBIOS table type-16 data for dimm:",
+ phosphor::logging::entry("DIMM:%d", dimmNum));
+}
+
+EccType Dimm::ecc(EccType value)
+{
+ return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::ecc(
+ value);
+}
+
uint16_t Dimm::memoryDataWidth(uint16_t value)
{
return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::