Revamped code for VPD parser
The commit removes all the pre-existing code from the branch
and pushes the revamped code.
Major modification includes:
- Movement from multi exe to single daemon model.
- Multithreaded approach to parse FRU VPD.
- Better error handling.
- Refactored code for performance optimization.
Note: This code supports all the existing functionalities as it is.
Change-Id: I1ddce1f0725ac59020b72709689a1013643bda8b
Signed-off-by: Sunny Srivastava <sunnsr25@in.ibm.com>
diff --git a/vpd-manager/src/ddimm_parser.cpp b/vpd-manager/src/ddimm_parser.cpp
new file mode 100644
index 0000000..0da4ddc
--- /dev/null
+++ b/vpd-manager/src/ddimm_parser.cpp
@@ -0,0 +1,393 @@
+#include "ddimm_parser.hpp"
+
+#include "constants.hpp"
+#include "exceptions.hpp"
+
+#include <cmath>
+#include <cstdint>
+#include <iostream>
+#include <numeric>
+#include <string>
+
+namespace vpd
+{
+
+static constexpr auto SDRAM_DENSITY_PER_DIE_24GB = 24;
+static constexpr auto SDRAM_DENSITY_PER_DIE_32GB = 32;
+static constexpr auto SDRAM_DENSITY_PER_DIE_48GB = 48;
+static constexpr auto SDRAM_DENSITY_PER_DIE_64GB = 64;
+static constexpr auto SDRAM_DENSITY_PER_DIE_UNDEFINED = 0;
+
+static constexpr auto PRIMARY_BUS_WIDTH_32_BITS = 32;
+static constexpr auto PRIMARY_BUS_WIDTH_UNUSED = 0;
+
+bool DdimmVpdParser::checkValidValue(uint8_t i_ByteValue, uint8_t i_shift,
+ uint8_t i_minValue, uint8_t i_maxValue)
+{
+ bool l_isValid = true;
+ uint8_t l_ByteValue = i_ByteValue >> i_shift;
+ if ((l_ByteValue > i_maxValue) || (l_ByteValue < i_minValue))
+ {
+ logging::logMessage(
+ "Non valid Value encountered value[" + std::to_string(l_ByteValue) +
+ "] range [" + std::to_string(i_minValue) + ".." +
+ std::to_string(i_maxValue) + "] found ");
+ return false;
+ }
+ return l_isValid;
+}
+
+uint8_t DdimmVpdParser::getDdr5DensityPerDie(uint8_t i_ByteValue)
+{
+ uint8_t l_densityPerDie = SDRAM_DENSITY_PER_DIE_UNDEFINED;
+ if (i_ByteValue < constants::VALUE_5)
+ {
+ l_densityPerDie = i_ByteValue * constants::VALUE_4;
+ }
+ else
+ {
+ switch (i_ByteValue)
+ {
+ case constants::VALUE_5:
+ l_densityPerDie = SDRAM_DENSITY_PER_DIE_24GB;
+ break;
+
+ case constants::VALUE_6:
+ l_densityPerDie = SDRAM_DENSITY_PER_DIE_32GB;
+ break;
+
+ case constants::VALUE_7:
+ l_densityPerDie = SDRAM_DENSITY_PER_DIE_48GB;
+ break;
+
+ case constants::VALUE_8:
+ l_densityPerDie = SDRAM_DENSITY_PER_DIE_64GB;
+ break;
+
+ default:
+ logging::logMessage(
+ "default value encountered for density per die");
+ l_densityPerDie = SDRAM_DENSITY_PER_DIE_UNDEFINED;
+ break;
+ }
+ }
+ return l_densityPerDie;
+}
+
+uint8_t DdimmVpdParser::getDdr5DiePerPackage(uint8_t i_ByteValue)
+{
+ uint8_t l_DiePerPackage = constants::VALUE_0;
+ if (i_ByteValue < constants::VALUE_2)
+ {
+ l_DiePerPackage = i_ByteValue + constants::VALUE_1;
+ }
+ else
+ {
+ l_DiePerPackage =
+ pow(constants::VALUE_2, (i_ByteValue - constants::VALUE_1));
+ }
+ return l_DiePerPackage;
+}
+
+size_t DdimmVpdParser::getDdr5BasedDdimmSize(
+ types::BinaryVector::const_iterator i_iterator)
+{
+ size_t l_dimmSize = 0;
+
+ do
+ {
+ if (!checkValidValue(i_iterator[constants::SPD_BYTE_235] &
+ constants::MASK_BYTE_BITS_01,
+ constants::SHIFT_BITS_0, constants::VALUE_1,
+ constants::VALUE_3) ||
+ !checkValidValue(i_iterator[constants::SPD_BYTE_235] &
+ constants::MASK_BYTE_BITS_345,
+ constants::SHIFT_BITS_3, constants::VALUE_1,
+ constants::VALUE_3))
+ {
+ logging::logMessage(
+ "Capacity calculation failed for channels per DIMM. DDIMM Byte "
+ "235 value [" +
+ std::to_string(i_iterator[constants::SPD_BYTE_235]) + "]");
+ break;
+ }
+ uint8_t l_channelsPerPhy =
+ (((i_iterator[constants::SPD_BYTE_235] &
+ constants::MASK_BYTE_BITS_01)
+ ? constants::VALUE_1
+ : constants::VALUE_0) +
+ ((i_iterator[constants::SPD_BYTE_235] &
+ constants::MASK_BYTE_BITS_345)
+ ? constants::VALUE_1
+ : constants::VALUE_0));
+
+ uint8_t l_channelsPerDdimm =
+ (((i_iterator[constants::SPD_BYTE_235] &
+ constants::MASK_BYTE_BIT_6) >>
+ constants::VALUE_6) +
+ ((i_iterator[constants::SPD_BYTE_235] &
+ constants::MASK_BYTE_BIT_7) >>
+ constants::VALUE_7)) *
+ l_channelsPerPhy;
+
+ if (!checkValidValue(i_iterator[constants::SPD_BYTE_235] &
+ constants::MASK_BYTE_BITS_012,
+ constants::SHIFT_BITS_0, constants::VALUE_1,
+ constants::VALUE_3))
+ {
+ logging::logMessage(
+ "Capacity calculation failed for bus width per channel. DDIMM "
+ "Byte 235 value [" +
+ std::to_string(i_iterator[constants::SPD_BYTE_235]) + "]");
+ break;
+ }
+ uint8_t l_busWidthPerChannel =
+ (i_iterator[constants::SPD_BYTE_235] &
+ constants::MASK_BYTE_BITS_012)
+ ? PRIMARY_BUS_WIDTH_32_BITS
+ : PRIMARY_BUS_WIDTH_UNUSED;
+
+ if (!checkValidValue(i_iterator[constants::SPD_BYTE_4] &
+ constants::MASK_BYTE_BITS_567,
+ constants::SHIFT_BITS_5, constants::VALUE_0,
+ constants::VALUE_5))
+ {
+ logging::logMessage(
+ "Capacity calculation failed for die per package. DDIMM Byte 4 "
+ "value [" +
+ std::to_string(i_iterator[constants::SPD_BYTE_4]) + "]");
+ break;
+ }
+ uint8_t l_diePerPackage = getDdr5DiePerPackage(
+ (i_iterator[constants::SPD_BYTE_4] &
+ constants::MASK_BYTE_BITS_567) >>
+ constants::VALUE_5);
+
+ if (!checkValidValue(i_iterator[constants::SPD_BYTE_4] &
+ constants::MASK_BYTE_BITS_01234,
+ constants::SHIFT_BITS_0, constants::VALUE_1,
+ constants::VALUE_8))
+ {
+ logging::logMessage(
+ "Capacity calculation failed for SDRAM Density per Die. DDIMM "
+ "Byte 4 value [" +
+ std::to_string(i_iterator[constants::SPD_BYTE_4]) + "]");
+ break;
+ }
+ uint8_t l_densityPerDie = getDdr5DensityPerDie(
+ i_iterator[constants::SPD_BYTE_4] &
+ constants::MASK_BYTE_BITS_01234);
+
+ uint8_t l_ranksPerChannel = 0;
+
+ if (((i_iterator[constants::SPD_BYTE_234] &
+ constants::MASK_BYTE_BIT_7) >>
+ constants::VALUE_7))
+ {
+ l_ranksPerChannel = ((i_iterator[constants::SPD_BYTE_234] &
+ constants::MASK_BYTE_BITS_345) >>
+ constants::VALUE_3) +
+ constants::VALUE_1;
+ }
+ else if (((i_iterator[constants::SPD_BYTE_235] &
+ constants::MASK_BYTE_BIT_6) >>
+ constants::VALUE_6))
+ {
+ l_ranksPerChannel = (i_iterator[constants::SPD_BYTE_234] &
+ constants::MASK_BYTE_BITS_012) +
+ constants::VALUE_1;
+ }
+
+ if (!checkValidValue(i_iterator[constants::SPD_BYTE_6] &
+ constants::MASK_BYTE_BITS_567,
+ constants::SHIFT_BITS_5, constants::VALUE_0,
+ constants::VALUE_3))
+ {
+ logging::logMessage(
+ "Capacity calculation failed for dram width DDIMM Byte 6 value "
+ "[" +
+ std::to_string(i_iterator[constants::SPD_BYTE_6]) + "]");
+ break;
+ }
+ uint8_t l_dramWidth =
+ constants::VALUE_4 *
+ (constants::VALUE_1 << ((i_iterator[constants::SPD_BYTE_6] &
+ constants::MASK_BYTE_BITS_567) >>
+ constants::VALUE_5));
+
+ // DDIMM size is calculated in GB
+ l_dimmSize = (l_channelsPerDdimm * l_busWidthPerChannel *
+ l_diePerPackage * l_densityPerDie * l_ranksPerChannel) /
+ (8 * l_dramWidth);
+
+ } while (false);
+
+ return constants::CONVERT_GB_TO_KB * l_dimmSize;
+}
+
+size_t DdimmVpdParser::getDdr4BasedDdimmSize(
+ types::BinaryVector::const_iterator i_iterator)
+{
+ size_t l_dimmSize = 0;
+ try
+ {
+ uint8_t l_tmpValue = 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)
+ {
+ throw std::runtime_error(
+ "Bad data in VPD byte 4. Can't calculate SDRAM capacity and so "
+ "dimm size.\n ");
+ }
+
+ uint16_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)
+ {
+ throw std::runtime_error(
+ "Bad data in VPD byte 13. Can't calculate primary bus width "
+ "and so dimm size.");
+ }
+
+ uint8_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)
+ {
+ throw std::runtime_error(
+ "Bad data in VPD byte 12. Can't calculate SDRAM width and so "
+ "dimm size.");
+ }
+
+ uint8_t l_sdramWidth = 1;
+ l_sdramWidth = (l_sdramWidth << l_tmpValue) *
+ constants::JEDEC_SDRAM_WIDTH_MULTIPLIER;
+
+ /* 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)
+ {
+ throw std::runtime_error(
+ "Bad data in VPD byte 12, can't calculate number of ranks. Invalid data found.");
+ }
+
+ uint8_t l_logicalRanksPerDimm = l_tmpValue + 1;
+
+ // Determine is single load stack (3DS) or not
+ l_tmpValue = i_iterator[constants::SPD_BYTE_6] &
+ constants::JEDEC_SIGNAL_LOADING_MASK;
+
+ 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;
+
+ uint8_t l_dieCount = l_tmpValue + 1;
+ l_logicalRanksPerDimm *= l_dieCount;
+ }
+
+ l_dimmSize =
+ (l_sdramCapacity / constants::JEDEC_PRI_BUS_WIDTH_MULTIPLIER) *
+ (l_primaryBusWid / l_sdramWidth) * l_logicalRanksPerDimm;
+
+ // Converting dimm size from MB to KB
+ l_dimmSize *= constants::CONVERT_MB_TO_KB;
+ }
+ catch (const std::exception& l_ex)
+ {
+ // TODO:: Need an error log here
+ logging::logMessage("DDR4 DDIMM calculation is failed, reason: " +
+ std::string(l_ex.what()));
+ }
+ return l_dimmSize;
+}
+
+size_t
+ DdimmVpdParser::getDdimmSize(types::BinaryVector::const_iterator i_iterator)
+{
+ size_t l_dimmSize = 0;
+ if (i_iterator[constants::SPD_BYTE_2] == constants::SPD_DRAM_TYPE_DDR5)
+ {
+ l_dimmSize = getDdr5BasedDdimmSize(i_iterator);
+ }
+ else if (i_iterator[constants::SPD_BYTE_2] == constants::SPD_DRAM_TYPE_DDR4)
+ {
+ l_dimmSize = getDdr4BasedDdimmSize(i_iterator);
+ }
+ else
+ {
+ 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;
+}
+
+void DdimmVpdParser::readKeywords(
+ types::BinaryVector::const_iterator i_iterator)
+{
+ // collect DDIMM size value
+ auto l_dimmSize = getDdimmSize(i_iterator);
+ if (!l_dimmSize)
+ {
+ throw(DataException("Error: Calculated dimm size is 0."));
+ }
+
+ m_parsedVpdMap.emplace("MemorySizeInKB", l_dimmSize);
+ // point the i_iterator to DIMM data and skip "11S"
+ advance(i_iterator, constants::DDIMM_11S_BARCODE_START +
+ constants::DDIMM_11S_FORMAT_LEN);
+ types::BinaryVector l_partNumber(i_iterator,
+ i_iterator + constants::PART_NUM_LEN);
+
+ advance(i_iterator, constants::PART_NUM_LEN);
+ types::BinaryVector l_serialNumber(i_iterator,
+ i_iterator + constants::SERIAL_NUM_LEN);
+
+ advance(i_iterator, constants::SERIAL_NUM_LEN);
+ types::BinaryVector l_ccin(i_iterator, i_iterator + constants::CCIN_LEN);
+
+ m_parsedVpdMap.emplace("FN", l_partNumber);
+ m_parsedVpdMap.emplace("PN", move(l_partNumber));
+ m_parsedVpdMap.emplace("SN", move(l_serialNumber));
+ m_parsedVpdMap.emplace("CC", move(l_ccin));
+}
+
+types::VPDMapVariant DdimmVpdParser::parse()
+{
+ try
+ {
+ // Read the data and return the map
+ auto l_iterator = m_vpdVector.cbegin();
+ readKeywords(l_iterator);
+ return m_parsedVpdMap;
+ }
+ catch (const std::exception& exp)
+ {
+ logging::logMessage(exp.what());
+ throw exp;
+ }
+}
+
+} // namespace vpd