Adding ISDIMM support

Added ISDIMM support for Bonnell machine

Change-Id: Ifdb2fc9e2d38267c8eb6cd5848d30102ab48efd1
Signed-off-by: jinuthomas <jinu.joy.thomas@in.ibm.com>
diff --git a/vpd-parser/isdimm_vpd_parser.cpp b/vpd-parser/isdimm_vpd_parser.cpp
new file mode 100644
index 0000000..253203b
--- /dev/null
+++ b/vpd-parser/isdimm_vpd_parser.cpp
@@ -0,0 +1,339 @@
+#include "isdimm_vpd_parser.hpp"
+
+#include <iostream>
+#include <numeric>
+#include <string>
+
+namespace openpower
+{
+namespace vpd
+{
+namespace memory
+{
+namespace parser
+{
+static constexpr auto SPD_JEDEC_DDR4_SDRAM_CAP_MASK = 0x0F;
+static constexpr auto SPD_JEDEC_DDR4_PRI_BUS_WIDTH_MASK = 0x07;
+static constexpr auto SPD_JEDEC_DDR4_SDRAM_WIDTH_MASK = 0x07;
+static constexpr auto SPD_JEDEC_DDR4_NUM_RANKS_MASK = 0x38;
+static constexpr auto SPD_JEDEC_DDR4_DIE_COUNT_MASK = 0x70;
+static constexpr auto SPD_JEDEC_DDR4_SINGLE_LOAD_STACK = 0x02;
+static constexpr auto SPD_JEDEC_DDR4_SIGNAL_LOADING_MASK = 0x03;
+
+static constexpr auto SPD_JEDEC_DDR4_SDRAMCAP_MULTIPLIER = 256;
+static constexpr auto SPD_JEDEC_DDR4_PRI_BUS_WIDTH_MULTIPLIER = 8;
+static constexpr auto SPD_JEDEC_DDR4_SDRAM_WIDTH_MULTIPLIER = 4;
+static constexpr auto SPD_JEDEC_DDR4_SDRAMCAP_RESERVED = 8;
+static constexpr auto SPD_JEDEC_DDR4_4_RESERVED_BITS = 4;
+static constexpr auto SPD_JEDEC_DDR4_3_RESERVED_BITS = 3;
+static constexpr auto SPD_JEDEC_DDR4_DIE_COUNT_RIGHT_SHIFT = 4;
+
+static constexpr auto SPD_JEDEC_DDR4_MFG_ID_MSB_OFFSET = 321;
+static constexpr auto SPD_JEDEC_DDR4_MFG_ID_LSB_OFFSET = 320;
+static constexpr auto SPD_JEDEC_DDR4_SN_BYTE0_OFFSET = 325;
+static constexpr auto SPD_JEDEC_DDR4_SN_BYTE1_OFFSET = 326;
+static constexpr auto SPD_JEDEC_DDR4_SN_BYTE2_OFFSET = 327;
+static constexpr auto SPD_JEDEC_DDR4_SN_BYTE3_OFFSET = 328;
+static constexpr auto SPD_JEDEC_DDR4_SDRAM_DENSITY_BANK_OFFSET = 4;
+static constexpr auto SPD_JEDEC_DDR4_SDRAM_ADDR_OFFSET = 5;
+static constexpr auto SPD_JEDEC_DDR4_DRAM_PRI_PACKAGE_OFFSET = 6;
+static constexpr auto SPD_JEDEC_DDR4_DRAM_MODULE_ORG_OFFSET = 12;
+
+// DDR5 JEDEC specification constants
+static constexpr auto SPD_JEDEC_DDR5_SUB_CHANNELS_PER_DIMM = 235;
+static constexpr auto SPD_JEDEC_DDR5_SUB_CHANNELS_PER_DIMM_MASK = 0x60;
+static constexpr auto SPD_JEDEC_DDR5_PRI_BUS_WIDTH_PER_CHANNEL = 235;
+static constexpr auto SPD_JEDEC_DDR5_PRI_BUS_WIDTH_PER_CHANNEL_MASK = 0x07;
+static constexpr auto SPD_JEDEC_DDR5_SDRAM_IO_WIDTH_SYM_ALL = 6;
+static constexpr auto SPD_JEDEC_DDR5_SDRAM_IO_WIDTH_ASYM_EVEN = 6;
+static constexpr auto SPD_JEDEC_DDR5_SDRAM_IO_WIDTH_ASYM_ODD = 10;
+static constexpr auto SPD_JEDEC_DDR5_SDRAM_IO_WIDTH_MASK = 0xE0;
+static constexpr auto SPD_JEDEC_DDR5_DIE_PER_PKG_SYM_ALL = 4;
+static constexpr auto SPD_JEDEC_DDR5_DIE_PER_PKG_ASYM_EVEN = 4;
+static constexpr auto SPD_JEDEC_DDR5_DIE_PER_PKG_ASYM_ODD = 8;
+static constexpr auto SPD_JEDEC_DDR5_DIE_PER_PKG_MASK = 0xE0;
+static constexpr auto SPD_JEDEC_DDR5_SDRAM_DENSITY_PER_DIE_SYM_ALL = 4;
+static constexpr auto SPD_JEDEC_DDR5_SDRAM_DENSITY_PER_DIE_ASYM_EVEN = 4;
+static constexpr auto SPD_JEDEC_DDR5_SDRAM_DENSITY_PER_DIE_ASYM_ODD = 8;
+static constexpr auto SPD_JEDEC_DDR5_SDRAM_DENSITY_PER_DIE_MASK = 0x1F;
+static constexpr auto SPD_JEDEC_DDR5_RANK_MIX = 234;
+static constexpr auto SPD_JEDEC_DDR5_RANK_MIX_SYMMETRICAL_MASK = 0x40;
+
+auto isdimmVpdParser::getDDR4DimmCapacity(Binary::const_iterator& iterator)
+{
+    size_t tmp = 0, dimmSize = 0;
+
+    size_t sdramCap = 1, priBusWid = 1, sdramWid = 1, logicalRanksPerDimm = 1;
+    Byte dieCount = 1;
+
+    // NOTE: This calculation is Only for DDR4
+
+    // Calculate SDRAM  capacity
+    tmp = iterator[constants::SPD_BYTE_4] & SPD_JEDEC_DDR4_SDRAM_CAP_MASK;
+    /* Make sure the bits are not Reserved */
+    if (tmp >= SPD_JEDEC_DDR4_SDRAMCAP_RESERVED)
+    {
+        std::cerr
+            << "Bad data in spd byte 4. Can't calculate SDRAM capacity and so "
+               "dimm size.\n ";
+        return dimmSize;
+    }
+
+    sdramCap = (sdramCap << tmp) * SPD_JEDEC_DDR4_SDRAMCAP_MULTIPLIER;
+
+    /* Calculate Primary bus width */
+    tmp = iterator[constants::SPD_BYTE_13] & SPD_JEDEC_DDR4_PRI_BUS_WIDTH_MASK;
+    if (tmp >= SPD_JEDEC_DDR4_4_RESERVED_BITS)
+    {
+        std::cerr
+            << "Bad data in spd byte 13. Can't calculate primary bus width "
+               "and so dimm size.\n ";
+        return dimmSize;
+    }
+    priBusWid = (priBusWid << tmp) * SPD_JEDEC_DDR4_PRI_BUS_WIDTH_MULTIPLIER;
+
+    /* Calculate SDRAM width */
+    tmp = iterator[constants::SPD_BYTE_12] & SPD_JEDEC_DDR4_SDRAM_WIDTH_MASK;
+    if (tmp >= SPD_JEDEC_DDR4_4_RESERVED_BITS)
+    {
+        std::cerr
+            << "Bad data in vpd byte 12. Can't calculate SDRAM width and so "
+               "dimm size.\n ";
+        return dimmSize;
+    }
+    sdramWid = (sdramWid << tmp) * SPD_JEDEC_DDR4_SDRAM_WIDTH_MULTIPLIER;
+
+    tmp = iterator[constants::SPD_BYTE_6] & SPD_JEDEC_DDR4_SIGNAL_LOADING_MASK;
+
+    if (tmp == SPD_JEDEC_DDR4_SINGLE_LOAD_STACK)
+    {
+        // Fetch die count
+        tmp = iterator[constants::SPD_BYTE_6] & SPD_JEDEC_DDR4_DIE_COUNT_MASK;
+        tmp >>= SPD_JEDEC_DDR4_DIE_COUNT_RIGHT_SHIFT;
+        dieCount = tmp + 1;
+    }
+
+    /* Calculate Number of ranks */
+    tmp = iterator[constants::SPD_BYTE_12] & SPD_JEDEC_DDR4_NUM_RANKS_MASK;
+    tmp >>= SPD_JEDEC_DDR4_3_RESERVED_BITS;
+
+    if (tmp >= SPD_JEDEC_DDR4_4_RESERVED_BITS)
+    {
+        std::cerr << "Can't calculate number of ranks. Invalid data found.\n ";
+        return dimmSize;
+    }
+    logicalRanksPerDimm = (tmp + 1) * dieCount;
+
+    dimmSize = (sdramCap / SPD_JEDEC_DDR4_PRI_BUS_WIDTH_MULTIPLIER) *
+               (priBusWid / sdramWid) * logicalRanksPerDimm;
+
+    return dimmSize;
+}
+
+auto isdimmVpdParser::getDDR4PartNumber(Binary::const_iterator& iterator)
+{
+
+    char tmpPN[constants::PART_NUM_LEN + 1] = {'\0'};
+    sprintf(tmpPN, "%02X%02X%02X%X",
+            iterator[SPD_JEDEC_DDR4_SDRAM_DENSITY_BANK_OFFSET],
+            iterator[SPD_JEDEC_DDR4_SDRAM_ADDR_OFFSET],
+            iterator[SPD_JEDEC_DDR4_DRAM_PRI_PACKAGE_OFFSET],
+            iterator[SPD_JEDEC_DDR4_DRAM_MODULE_ORG_OFFSET] & 0x0F);
+    std::string partNumber(tmpPN, sizeof(tmpPN));
+    return partNumber;
+}
+
+auto isdimmVpdParser::getDDR4SerialNumber(Binary::const_iterator& iterator)
+{
+    char tmpSN[constants::SERIAL_NUM_LEN + 1] = {'\0'};
+    sprintf(tmpSN, "%02X%02X%02X%02X%02X%02X",
+            iterator[SPD_JEDEC_DDR4_MFG_ID_MSB_OFFSET],
+            iterator[SPD_JEDEC_DDR4_MFG_ID_LSB_OFFSET],
+            iterator[SPD_JEDEC_DDR4_SN_BYTE0_OFFSET],
+            iterator[SPD_JEDEC_DDR4_SN_BYTE1_OFFSET],
+            iterator[SPD_JEDEC_DDR4_SN_BYTE2_OFFSET],
+            iterator[SPD_JEDEC_DDR4_SN_BYTE3_OFFSET]);
+    std::string serialNumber(tmpSN, sizeof(tmpSN));
+    return serialNumber;
+}
+
+auto isdimmVpdParser::getDDR4FruNumber(const std::string& partNumber)
+{
+    // check for 128GB ISRDIMM not implemented
+    //(128GB 2RX4(8GX72) IS RDIMM 36*(16GBIT, 2H),1.2V 288PIN,1.2" ROHS) - NA
+
+    static std::unordered_map<std::string, std::string> pnFruMap = {
+        {"8421000", "78P4191"}, {"8421008", "78P4192"}, {"8529000", "78P4197"},
+        {"8529008", "78P4198"}, {"8529928", "78P4199"}, {"8529B28", "78P4200"},
+        {"8631008", "78P6815"}, {"8631928", "78P6925"}};
+
+    std::string fruNumber;
+    auto itr = pnFruMap.find(partNumber);
+    if (itr != pnFruMap.end())
+    {
+        fruNumber = itr->second;
+    }
+    else
+    {
+        fruNumber = "FFFFFFF";
+    }
+    return fruNumber;
+}
+
+auto isdimmVpdParser::getDDR4CCIN(const std::string& partNumber)
+{
+    static std::unordered_map<std::string, std::string> pnCCINMap = {
+        {"8421000", "324D"}, {"8421008", "324E"}, {"8529000", "324E"},
+        {"8529008", "324F"}, {"8529928", "325A"}, {"8529B28", "324C"},
+        {"8631008", "32BB"}, {"8631928", "32BC"}};
+
+    std::string ccin;
+    auto itr = pnCCINMap.find(partNumber);
+    if (itr != pnCCINMap.end())
+    {
+        ccin = itr->second;
+    }
+    else
+    {
+        ccin = "XXXX";
+    }
+    return ccin;
+}
+
+auto isdimmVpdParser::getDDR5DimmCapacity(Binary::const_iterator& iterator)
+{
+    // dummy implementation to be updated when required
+    size_t dimmSize = 0;
+    (void)iterator;
+    return dimmSize;
+}
+
+auto isdimmVpdParser::getDDR5PartNumber(Binary::const_iterator& iterator)
+{
+    // dummy implementation to be updated when required
+    std::string partNumber;
+    (void)iterator;
+    partNumber = "0123456";
+    return partNumber;
+}
+
+auto isdimmVpdParser::getDDR5SerialNumber(Binary::const_iterator& iterator)
+{
+    // dummy implementation to be updated when required
+    std::string serialNumber;
+    (void)iterator;
+    serialNumber = "444444444444";
+    return serialNumber;
+}
+
+auto isdimmVpdParser::getDDR5FruNumber(const std::string& partNumber)
+{
+    // dummy implementation to be updated when required
+    static std::unordered_map<std::string, std::string> pnFruMap = {
+        {"1234567", "XXXXXXX"}};
+
+    std::string fruNumber;
+    auto itr = pnFruMap.find(partNumber);
+    if (itr != pnFruMap.end())
+    {
+        fruNumber = itr->second;
+    }
+    else
+    {
+        fruNumber = "FFFFFFF";
+    }
+    return fruNumber;
+}
+
+auto isdimmVpdParser::getDDR5CCIN(const std::string& partNumber)
+{
+    // dummy implementation to be updated when required
+    static std::unordered_map<std::string, std::string> pnCCINMap = {
+        {"1234567", "XXXX"}};
+
+    std::string ccin;
+    auto itr = pnCCINMap.find(partNumber);
+    if (itr != pnCCINMap.end())
+    {
+        ccin = itr->second;
+    }
+    else
+    {
+        ccin = "XXXX";
+    }
+    return ccin;
+}
+
+kwdVpdMap isdimmVpdParser::readKeywords(Binary::const_iterator& iterator)
+{
+    inventory::KeywordVpdMap keywordValueMap{};
+    if ((iterator[constants::SPD_BYTE_2] & constants::SPD_BYTE_MASK) ==
+        constants::SPD_DRAM_TYPE_DDR5)
+    {
+        auto dimmSize = getDDR5DimmCapacity(iterator);
+        if (!dimmSize)
+        {
+            std::cerr << "Error: Calculated dimm size is 0.";
+        }
+        else if (dimmSize < constants::CONVERT_MB_TO_KB)
+        {
+            keywordValueMap.emplace("MemorySizeInMB", dimmSize);
+        }
+        else
+        {
+            size_t dimmCapacityInGB = dimmSize / constants::CONVERT_MB_TO_KB;
+            keywordValueMap.emplace("MemorySizeInGB", dimmCapacityInGB);
+        }
+        auto partNumber = getDDR5PartNumber(iterator);
+        keywordValueMap.emplace("PN", move(partNumber));
+        auto fruNumber = getDDR5FruNumber(partNumber);
+        keywordValueMap.emplace("FN", move(fruNumber));
+        auto serialNumber = getDDR5SerialNumber(iterator);
+        keywordValueMap.emplace("SN", move(serialNumber));
+        auto ccin = getDDR5CCIN(partNumber);
+        keywordValueMap.emplace("CC", move(ccin));
+    }
+    else if ((iterator[constants::SPD_BYTE_2] & constants::SPD_BYTE_MASK) ==
+             constants::SPD_DRAM_TYPE_DDR4)
+    {
+        auto dimmSize = getDDR4DimmCapacity(iterator);
+        if (!dimmSize)
+        {
+            std::cerr << "Error: Calculated dimm size is 0.";
+        }
+        else if (dimmSize < constants::CONVERT_MB_TO_KB)
+        {
+            keywordValueMap.emplace("MemorySizeInMB", dimmSize);
+        }
+        else
+        {
+            size_t dimmCapacityInGB = dimmSize / constants::CONVERT_MB_TO_KB;
+            keywordValueMap.emplace("MemorySizeInGB", dimmCapacityInGB);
+        }
+        size_t dimmCapacityInGB = dimmSize / constants::CONVERT_MB_TO_KB;
+        keywordValueMap.emplace("MemorySizeInGB", dimmCapacityInGB);
+        auto partNumber = getDDR4PartNumber(iterator);
+        keywordValueMap.emplace("PN", move(partNumber));
+        auto fruNumber = getDDR4FruNumber(partNumber);
+        keywordValueMap.emplace("FN", move(fruNumber));
+        auto serialNumber = getDDR4SerialNumber(iterator);
+        keywordValueMap.emplace("SN", move(serialNumber));
+        auto ccin = getDDR4CCIN(partNumber);
+        keywordValueMap.emplace("CC", move(ccin));
+    }
+    return keywordValueMap;
+}
+
+std::variant<kwdVpdMap, Store> isdimmVpdParser::parse()
+{
+    // Read the data and return the map
+    auto iterator = memVpd.cbegin();
+    auto vpdDataMap = readKeywords(iterator);
+
+    return vpdDataMap;
+}
+
+} // namespace parser
+} // namespace memory
+} // namespace vpd
+} // namespace openpower
\ No newline at end of file