From 4b9b8df1e30f297d35da3409210ddd75113e06fd Mon Sep 17 00:00:00 2001 From: Anupama B R Date: Wed, 16 Oct 2024 01:16:47 -0500 Subject: [PATCH] Support DDR4 DDIMM parse This commit adds the code to support parsing of DDR4 DDIMM type VPD. ParserFactory is updated to handle the DDR4 type to get the DDIMM VPD parsing instance for DDR4 DDIMM and DdimmVpdParser class updated to handle DDR4 DDIMM VPD parsing with new API to calculate the DDR4 DDIMM size. Tested the changes by running vpd-manager application, observed DDIMM parser is selected for DDR4 DDIMM EEPROM files and parsing is successful. And also observed, DDIMM size is calculated correctly for DDR4 DDIMMs. Signed-off-by: Anupama B R --- include/constants.hpp | 15 ++++++ include/ddimm_parser.hpp | 9 ++++ src/ddimm_parser.cpp | 99 ++++++++++++++++++++++++++++++++++++++-- src/parser_factory.cpp | 1 + 4 files changed, 121 insertions(+), 3 deletions(-) diff --git a/include/constants.hpp b/include/constants.hpp index 680b087f..d96e8090 100644 --- a/include/constants.hpp +++ b/include/constants.hpp @@ -44,6 +44,21 @@ static constexpr auto SPD_MODULE_TYPE_DDIMM = 0x0A; static constexpr auto SPD_DRAM_TYPE_DDR5 = 0x12; static constexpr auto SPD_DRAM_TYPE_DDR4 = 0x0C; +static constexpr auto JEDEC_SDRAM_CAP_MASK = 0x0F; +static constexpr auto JEDEC_PRI_BUS_WIDTH_MASK = 0x07; +static constexpr auto JEDEC_SDRAM_WIDTH_MASK = 0x07; +static constexpr auto JEDEC_NUM_RANKS_MASK = 0x38; +static constexpr auto JEDEC_DIE_COUNT_MASK = 0x70; +static constexpr auto JEDEC_SINGLE_LOAD_STACK = 0x02; +static constexpr auto JEDEC_SIGNAL_LOADING_MASK = 0x03; + +static constexpr auto JEDEC_SDRAMCAP_MULTIPLIER = 256; +static constexpr auto JEDEC_PRI_BUS_WIDTH_MULTIPLIER = 8; +static constexpr auto JEDEC_SDRAM_WIDTH_MULTIPLIER = 4; +static constexpr auto JEDEC_SDRAMCAP_RESERVED = 6; +static constexpr auto JEDEC_RESERVED_BITS = 3; +static constexpr auto JEDEC_DIE_COUNT_RIGHT_SHIFT = 4; + static constexpr auto LAST_KW = "PF"; static constexpr auto POUND_KW = '#'; static constexpr auto POUND_KW_PREFIX = "PD_"; diff --git a/include/ddimm_parser.hpp b/include/ddimm_parser.hpp index 7b168a1c..a53ed172 100644 --- a/include/ddimm_parser.hpp +++ b/include/ddimm_parser.hpp @@ -77,6 +77,15 @@ class DdimmVpdParser : public ParserInterface size_t getDdr5BasedDdimmSize(types::BinaryVector::const_iterator i_iterator); + /** + * @brief This function calculates DDR4 based DDIMM's capacity + * + * @param[in] i_iterator - iterator to buffer containing VPD + * @return calculated size or 0 in case of any error. + */ + size_t + getDdr4BasedDdimmSize(types::BinaryVector::const_iterator i_iterator); + /** * @brief This function calculates DDR5 based die per package * diff --git a/src/ddimm_parser.cpp b/src/ddimm_parser.cpp index 712a50df..d71e5c1e 100644 --- a/src/ddimm_parser.cpp +++ b/src/ddimm_parser.cpp @@ -200,6 +200,94 @@ size_t DdimmVpdParser::getDdr5BasedDdimmSize( return constants::CONVERT_GB_TO_KB * l_dimmSize; } +size_t DdimmVpdParser::getDdr4BasedDdimmSize( + types::BinaryVector::const_iterator i_iterator) +{ + size_t l_tmpValue = 0, l_dimmSize = 0; + + // Calculate SDRAM capacity + l_tmpValue = i_iterator[constants::SPD_BYTE_4] & + constants::JEDEC_SDRAM_CAP_MASK; + + /* Make sure the bits are not Reserved */ + if (l_tmpValue > constants::JEDEC_SDRAMCAP_RESERVED) + { + logging::logMessage( + "Bad data in vpd byte 4. Can't calculate SDRAM capacity and so " + "dimm size.\n "); + return l_dimmSize; + } + + size_t l_sdramCapacity = 1; + l_sdramCapacity = (l_sdramCapacity << l_tmpValue) * + constants::JEDEC_SDRAMCAP_MULTIPLIER; + + /* Calculate Primary bus width */ + l_tmpValue = i_iterator[constants::SPD_BYTE_13] & + constants::JEDEC_PRI_BUS_WIDTH_MASK; + + if (l_tmpValue > constants::JEDEC_RESERVED_BITS) + { + logging::logMessage( + "Bad data in vpd byte 13. Can't calculate primary bus width " + "and so dimm size."); + return l_dimmSize; + } + + size_t l_primaryBusWid = 1; + l_primaryBusWid = (l_primaryBusWid << l_tmpValue) * + constants::JEDEC_PRI_BUS_WIDTH_MULTIPLIER; + + /* Calculate SDRAM width */ + l_tmpValue = i_iterator[constants::SPD_BYTE_12] & + constants::JEDEC_SDRAM_WIDTH_MASK; + + if (l_tmpValue > constants::JEDEC_RESERVED_BITS) + { + logging::logMessage( + "Bad data in vpd byte 12. Can't calculate SDRAM width and so " + "dimm size."); + return l_dimmSize; + } + + size_t l_sdramWidth = 1; + l_sdramWidth = (l_sdramWidth << l_tmpValue) * + constants::JEDEC_SDRAM_WIDTH_MULTIPLIER; + + // Calculate die count + l_tmpValue = i_iterator[constants::SPD_BYTE_6] & + constants::JEDEC_SIGNAL_LOADING_MASK; + uint8_t l_dieCount = 1; + + if (l_tmpValue == constants::JEDEC_SINGLE_LOAD_STACK) + { + // Fetch die count + l_tmpValue = i_iterator[constants::SPD_BYTE_6] & + constants::JEDEC_DIE_COUNT_MASK; + l_tmpValue >>= constants::JEDEC_DIE_COUNT_RIGHT_SHIFT; + l_dieCount = l_tmpValue + 1; + } + + /* Calculate Number of ranks */ + l_tmpValue = i_iterator[constants::SPD_BYTE_12] & + constants::JEDEC_NUM_RANKS_MASK; + l_tmpValue >>= constants::JEDEC_RESERVED_BITS; + + if (l_tmpValue > constants::JEDEC_RESERVED_BITS) + { + logging::logMessage( + "Can't calculate number of ranks. Invalid data found."); + return l_dimmSize; + } + + size_t l_logicalRanksPerDimm = (l_tmpValue + 1) * l_dieCount; + + l_dimmSize = (l_sdramCapacity / constants::JEDEC_PRI_BUS_WIDTH_MULTIPLIER) * + (l_primaryBusWid / l_sdramWidth) * l_logicalRanksPerDimm; + + return (constants::CONVERT_MB_TO_KB * l_dimmSize); +} + size_t DdimmVpdParser::getDdimmSize(types::BinaryVector::const_iterator i_iterator) { @@ -209,11 +297,16 @@ size_t { l_dimmSize = getDdr5BasedDdimmSize(i_iterator); } + else if ((i_iterator[constants::SPD_BYTE_2] & constants::SPD_BYTE_MASK) == + constants::SPD_DRAM_TYPE_DDR4) + { + l_dimmSize = getDdr4BasedDdimmSize(i_iterator); + } else { - logging::logMessage("Error: DDIMM is not DDR5. DDIMM Byte 2 value [" + - std::to_string(i_iterator[constants::SPD_BYTE_2]) + - "]"); + logging::logMessage( + "Error: DDIMM is neither DDR4 nor DDR5. DDIMM Byte 2 value [" + + std::to_string(i_iterator[constants::SPD_BYTE_2]) + "]"); } return l_dimmSize; } diff --git a/src/parser_factory.cpp b/src/parser_factory.cpp index 01b9b3d6..e5755b33 100644 --- a/src/parser_factory.cpp +++ b/src/parser_factory.cpp @@ -124,6 +124,7 @@ std::shared_ptr } case vpdType::DDR5_DDIMM_MEMORY_VPD: + case vpdType::DDR4_DDIMM_MEMORY_VPD: { logging::logMessage("DDIMM parser selected for VPD file path: " + i_vpdFilePath);