blob: 4a0ac7c67ac3f4ce4392bee0b3f08e7e7864191e [file] [log] [blame]
#include "memory_vpd_parser.hpp"
#include <cmath>
#include <cstdint>
#include <iostream>
#include <numeric>
#include <string>
namespace openpower
{
namespace vpd
{
namespace memory
{
namespace parser
{
using namespace inventory;
using namespace constants;
using namespace std;
using namespace openpower::vpd::parser;
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 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;
static constexpr auto DRAM_MANUFACTURER_ID_OFFSET = 0x228;
static constexpr auto DRAM_MANUFACTURER_ID_LENGTH = 0x02;
bool memoryVpdParser::checkValidValue(uint8_t l_ByteValue, uint8_t shift,
uint8_t minValue, uint8_t maxValue)
{
l_ByteValue = l_ByteValue >> shift;
if ((l_ByteValue > maxValue) || (l_ByteValue < minValue))
{
cout << "Non valid Value encountered value[" << l_ByteValue
<< "] range [" << minValue << ".." << maxValue << "] found "
<< " " << endl;
return false;
}
else
{
return true;
}
}
uint8_t memoryVpdParser::getDDR5DensityPerDie(uint8_t l_ByteValue)
{
uint8_t l_densityPerDie = SDRAM_DENSITY_PER_DIE_UNDEFINED;
if (l_ByteValue < constants::VALUE_5)
{
l_densityPerDie = l_ByteValue * constants::VALUE_4;
}
else
{
switch (l_ByteValue)
{
case VALUE_5:
l_densityPerDie = SDRAM_DENSITY_PER_DIE_24GB;
break;
case VALUE_6:
l_densityPerDie = SDRAM_DENSITY_PER_DIE_32GB;
break;
case VALUE_7:
l_densityPerDie = SDRAM_DENSITY_PER_DIE_48GB;
break;
case VALUE_8:
l_densityPerDie = SDRAM_DENSITY_PER_DIE_64GB;
break;
default:
cout << "default value encountered for density per die" << endl;
l_densityPerDie = SDRAM_DENSITY_PER_DIE_UNDEFINED;
break;
}
}
return l_densityPerDie;
}
uint8_t memoryVpdParser::getDDR5DiePerPackage(uint8_t l_ByteValue)
{
uint8_t l_DiePerPackage = constants::VALUE_0;
if (l_ByteValue < constants::VALUE_2)
{
l_DiePerPackage = l_ByteValue + constants::VALUE_1;
}
else
{
l_DiePerPackage =
pow(constants::VALUE_2, (l_ByteValue - constants::VALUE_1));
}
return l_DiePerPackage;
}
auto memoryVpdParser::getDdr5BasedDDimmSize(Binary::const_iterator iterator)
{
size_t dimmSize = 0;
do
{
if (!checkValidValue(iterator[constants::SPD_BYTE_235] &
constants::MASK_BYTE_BITS_01,
constants::SHIFT_BITS_0, constants::VALUE_1,
constants::VALUE_3) ||
!checkValidValue(iterator[constants::SPD_BYTE_235] &
constants::MASK_BYTE_BITS_345,
constants::SHIFT_BITS_3, constants::VALUE_1,
constants::VALUE_3))
{
std::cerr
<< "Capacity calculation failed for channels per DIMM. DDIMM "
"Byte 235 value ["
<< iterator[constants::SPD_BYTE_235] << "]";
break;
}
uint8_t l_channelsPerPhy =
(((iterator[constants::SPD_BYTE_235] & constants::MASK_BYTE_BITS_01)
? constants::VALUE_1
: constants::VALUE_0) +
((iterator[constants::SPD_BYTE_235] &
constants::MASK_BYTE_BITS_345)
? constants::VALUE_1
: constants::VALUE_0));
uint8_t l_channelsPerDdimm =
(((iterator[constants::SPD_BYTE_235] &
constants::MASK_BYTE_BITS_6) >>
constants::VALUE_6) +
((iterator[constants::SPD_BYTE_235] &
constants::MASK_BYTE_BITS_7) >>
constants::VALUE_7)) *
l_channelsPerPhy;
if (!checkValidValue(iterator[constants::SPD_BYTE_235] &
constants::MASK_BYTE_BITS_012,
constants::SHIFT_BITS_0, constants::VALUE_1,
constants::VALUE_3))
{
std::cerr
<< "Capacity calculation failed for bus width per channel. "
"DDIMM Byte 235 value ["
<< iterator[constants::SPD_BYTE_235] << "]";
break;
}
uint8_t l_busWidthPerChannel =
(iterator[constants::SPD_BYTE_235] & constants::MASK_BYTE_BITS_012)
? PRIMARY_BUS_WIDTH_32_BITS
: PRIMARY_BUS_WIDTH_UNUSED;
if (!checkValidValue(
iterator[constants::SPD_BYTE_4] & constants::MASK_BYTE_BITS_567,
constants::SHIFT_BITS_5, constants::VALUE_0,
constants::VALUE_5))
{
std::cerr
<< "Capacity calculation failed for die per package. DDIMM "
"Byte 4 value ["
<< iterator[constants::SPD_BYTE_4] << "]";
break;
}
uint8_t l_diePerPackage = getDDR5DiePerPackage(
(iterator[constants::SPD_BYTE_4] & constants::MASK_BYTE_BITS_567) >>
constants::VALUE_5);
if (!checkValidValue(iterator[constants::SPD_BYTE_4] &
constants::MASK_BYTE_BITS_01234,
constants::SHIFT_BITS_0, constants::VALUE_1,
constants::VALUE_8))
{
std::cerr
<< "Capacity calculation failed for SDRAM Density per Die. "
"DDIMM Byte 4 value ["
<< iterator[constants::SPD_BYTE_4] << "]";
break;
}
uint8_t l_densityPerDie = getDDR5DensityPerDie(
iterator[constants::SPD_BYTE_4] & constants::MASK_BYTE_BITS_01234);
uint8_t l_ranksPerChannel = 0;
if (((iterator[constants::SPD_BYTE_235] &
constants::MASK_BYTE_BITS_7) >>
constants::VALUE_7))
{
l_ranksPerChannel = ((iterator[constants::SPD_BYTE_234] &
constants::MASK_BYTE_BITS_345) >>
constants::VALUE_3) +
constants::VALUE_1;
}
else if (((iterator[constants::SPD_BYTE_235] &
constants::MASK_BYTE_BITS_6) >>
constants::VALUE_6))
{
l_ranksPerChannel = (iterator[constants::SPD_BYTE_234] &
constants::MASK_BYTE_BITS_012) +
constants::VALUE_1;
}
#if 0
// Old Style capacity calculation kept for reference
// will be removed later
uint8_t l_ranksPerChannel =
(((iterator[constants::SPD_BYTE_234] &
constants::MASK_BYTE_BITS_345) >>
constants::VALUE_3) *
((iterator[constants::SPD_BYTE_235] &
constants::MASK_BYTE_BITS_7) >>
constants::VALUE_7)) +
((iterator[constants::SPD_BYTE_234] &
constants::MASK_BYTE_BITS_012) +
constants::VALUE_2 * ((iterator[constants::SPD_BYTE_235] &
constants::MASK_BYTE_BITS_6) >>
constants::VALUE_6));
#endif
if (!checkValidValue(
iterator[constants::SPD_BYTE_6] & constants::MASK_BYTE_BITS_567,
constants::SHIFT_BITS_5, constants::VALUE_0,
constants::VALUE_3))
{
std::cout
<< "Capacity calculation failed for dram width DDIMM Byte 6 value ["
<< iterator[constants::SPD_BYTE_6] << "]";
break;
}
uint8_t l_dramWidth =
VALUE_4 * (VALUE_1 << ((iterator[constants::SPD_BYTE_6] &
constants::MASK_BYTE_BITS_567) >>
constants::VALUE_5));
dimmSize = (l_channelsPerDdimm * l_busWidthPerChannel *
l_diePerPackage * l_densityPerDie * l_ranksPerChannel) /
(8 * l_dramWidth);
} while (false);
return constants::CONVERT_GB_TO_KB * dimmSize;
}
auto memoryVpdParser::getDdr4BasedDDimmSize(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[SPD_BYTE_4] & JEDEC_SDRAM_CAP_MASK;
/* Make sure the bits are not Reserved */
if (tmp > JEDEC_SDRAMCAP_RESERVED)
{
cerr << "Bad data in vpd byte 4. Can't calculate SDRAM capacity and so "
"dimm size.\n ";
return dimmSize;
}
sdramCap = (sdramCap << tmp) * JEDEC_SDRAMCAP_MULTIPLIER;
/* Calculate Primary bus width */
tmp = iterator[SPD_BYTE_13] & JEDEC_PRI_BUS_WIDTH_MASK;
if (tmp > JEDEC_RESERVED_BITS)
{
cerr << "Bad data in vpd byte 13. Can't calculate primary bus width "
"and so dimm size.\n ";
return dimmSize;
}
priBusWid = (priBusWid << tmp) * JEDEC_PRI_BUS_WIDTH_MULTIPLIER;
/* Calculate SDRAM width */
tmp = iterator[SPD_BYTE_12] & JEDEC_SDRAM_WIDTH_MASK;
if (tmp > JEDEC_RESERVED_BITS)
{
cerr << "Bad data in vpd byte 12. Can't calculate SDRAM width and so "
"dimm size.\n ";
return dimmSize;
}
sdramWid = (sdramWid << tmp) * JEDEC_SDRAM_WIDTH_MULTIPLIER;
tmp = iterator[SPD_BYTE_6] & JEDEC_SIGNAL_LOADING_MASK;
if (tmp == JEDEC_SINGLE_LOAD_STACK)
{
// Fetch die count
tmp = iterator[SPD_BYTE_6] & JEDEC_DIE_COUNT_MASK;
tmp >>= JEDEC_DIE_COUNT_RIGHT_SHIFT;
dieCount = tmp + 1;
}
/* Calculate Number of ranks */
tmp = iterator[SPD_BYTE_12] & JEDEC_NUM_RANKS_MASK;
tmp >>= JEDEC_RESERVED_BITS;
if (tmp > JEDEC_RESERVED_BITS)
{
cerr << "Can't calculate number of ranks. Invalid data found.\n ";
return dimmSize;
}
logicalRanksPerDimm = (tmp + 1) * dieCount;
dimmSize = (sdramCap / JEDEC_PRI_BUS_WIDTH_MULTIPLIER) *
(priBusWid / sdramWid) * logicalRanksPerDimm;
return constants::CONVERT_MB_TO_KB * dimmSize;
}
size_t memoryVpdParser::getDDimmSize(Binary::const_iterator iterator)
{
size_t dimmSize = 0;
if ((iterator[constants::SPD_BYTE_2] & constants::SPD_BYTE_MASK) ==
constants::SPD_DRAM_TYPE_DDR4)
{
dimmSize = getDdr4BasedDDimmSize(iterator);
}
else if ((iterator[constants::SPD_BYTE_2] & constants::SPD_BYTE_MASK) ==
constants::SPD_DRAM_TYPE_DDR5)
{
dimmSize = getDdr5BasedDDimmSize(iterator);
}
else
{
cerr << "Error: DDIMM is neither DDR4 nor DDR5. DDIMM Byte 2 value ["
<< iterator[constants::SPD_BYTE_2] << "]";
}
return dimmSize;
}
kwdVpdMap memoryVpdParser::readKeywords(Binary::const_iterator iterator)
{
KeywordVpdMap map{};
// collect Dimm size value
auto dimmSize = getDDimmSize(iterator);
if (!dimmSize)
{
cerr << "Error: Calculated dimm size is 0.";
}
map.emplace("MemorySizeInKB", dimmSize);
// point the iterator to DIMM data and skip "11S"
advance(iterator, MEMORY_VPD_DATA_START + 3);
Binary partNumber(iterator, iterator + PART_NUM_LEN);
advance(iterator, PART_NUM_LEN);
Binary serialNumber(iterator, iterator + SERIAL_NUM_LEN);
advance(iterator, SERIAL_NUM_LEN);
Binary ccin(iterator, iterator + CCIN_LEN);
Binary mfgId(DRAM_MANUFACTURER_ID_LENGTH);
std::copy_n((memVpd.cbegin() + DRAM_MANUFACTURER_ID_OFFSET),
DRAM_MANUFACTURER_ID_LENGTH, mfgId.begin());
map.emplace("FN", partNumber);
map.emplace("PN", move(partNumber));
map.emplace("SN", move(serialNumber));
map.emplace("CC", move(ccin));
map.emplace("DI", move(mfgId));
return map;
}
variant<kwdVpdMap, Store> memoryVpdParser::parse()
{
// Read the data and return the map
auto iterator = memVpd.cbegin();
auto vpdDataMap = readKeywords(iterator);
return vpdDataMap;
}
std::string memoryVpdParser::getInterfaceName() const
{
return memVpdInf;
}
} // namespace parser
} // namespace memory
} // namespace vpd
} // namespace openpower