1 #include "memory_vpd_parser.hpp" 2 3 #include <iostream> 4 #include <numeric> 5 #include <string> 6 7 namespace openpower 8 { 9 namespace vpd 10 { 11 namespace memory 12 { 13 namespace parser 14 { 15 using namespace inventory; 16 using namespace constants; 17 using namespace std; 18 using namespace openpower::vpd::parser; 19 20 static constexpr auto MEM_BYTE_4 = 4; 21 static constexpr auto MEM_BYTE_6 = 6; 22 static constexpr auto MEM_BYTE_12 = 12; 23 static constexpr auto MEM_BYTE_13 = 13; 24 static constexpr auto JEDEC_SDRAM_CAP_MASK = 0x0F; 25 static constexpr auto JEDEC_PRI_BUS_WIDTH_MASK = 0x07; 26 static constexpr auto JEDEC_SDRAM_WIDTH_MASK = 0x07; 27 static constexpr auto JEDEC_NUM_RANKS_MASK = 0x38; 28 static constexpr auto JEDEC_DIE_COUNT_MASK = 0x70; 29 static constexpr auto JEDEC_SINGLE_LOAD_STACK = 0x02; 30 static constexpr auto JEDEC_SIGNAL_LOADING_MASK = 0x03; 31 32 static constexpr auto JEDEC_SDRAMCAP_MULTIPLIER = 256; 33 static constexpr auto JEDEC_PRI_BUS_WIDTH_MULTIPLIER = 8; 34 static constexpr auto JEDEC_SDRAM_WIDTH_MULTIPLIER = 4; 35 static constexpr auto JEDEC_SDRAMCAP_RESERVED = 6; 36 static constexpr auto JEDEC_RESERVED_BITS = 3; 37 static constexpr auto JEDEC_DIE_COUNT_RIGHT_SHIFT = 4; 38 39 auto memoryVpdParser::getDimmSize(Binary::const_iterator iterator) 40 { 41 size_t tmp = 0, dimmSize = 0; 42 43 size_t sdramCap = 1, priBusWid = 1, sdramWid = 1, logicalRanksPerDimm = 1; 44 Byte dieCount = 1; 45 46 // NOTE: This calculation is Only for DDR4 47 48 // Calculate SDRAM capacity 49 tmp = iterator[MEM_BYTE_4] & JEDEC_SDRAM_CAP_MASK; 50 /* Make sure the bits are not Reserved */ 51 if (tmp > JEDEC_SDRAMCAP_RESERVED) 52 { 53 cerr << "Bad data in vpd byte 4. Can't calculate SDRAM capacity and so " 54 "dimm size.\n "; 55 return dimmSize; 56 } 57 58 sdramCap = (sdramCap << tmp) * JEDEC_SDRAMCAP_MULTIPLIER; 59 60 /* Calculate Primary bus width */ 61 tmp = iterator[MEM_BYTE_13] & JEDEC_PRI_BUS_WIDTH_MASK; 62 if (tmp > JEDEC_RESERVED_BITS) 63 { 64 cerr << "Bad data in vpd byte 13. Can't calculate primary bus width " 65 "and so dimm size.\n "; 66 return dimmSize; 67 } 68 priBusWid = (priBusWid << tmp) * JEDEC_PRI_BUS_WIDTH_MULTIPLIER; 69 70 /* Calculate SDRAM width */ 71 tmp = iterator[MEM_BYTE_12] & JEDEC_SDRAM_WIDTH_MASK; 72 if (tmp > JEDEC_RESERVED_BITS) 73 { 74 cerr << "Bad data in vpd byte 12. Can't calculate SDRAM width and so " 75 "dimm size.\n "; 76 return dimmSize; 77 } 78 sdramWid = (sdramWid << tmp) * JEDEC_SDRAM_WIDTH_MULTIPLIER; 79 80 tmp = iterator[MEM_BYTE_6] & JEDEC_SIGNAL_LOADING_MASK; 81 82 if (tmp == JEDEC_SINGLE_LOAD_STACK) 83 { 84 // Fetch die count 85 tmp = iterator[MEM_BYTE_6] & JEDEC_DIE_COUNT_MASK; 86 tmp >>= JEDEC_DIE_COUNT_RIGHT_SHIFT; 87 dieCount = tmp + 1; 88 } 89 90 /* Calculate Number of ranks */ 91 tmp = iterator[MEM_BYTE_12] & JEDEC_NUM_RANKS_MASK; 92 tmp >>= JEDEC_RESERVED_BITS; 93 94 if (tmp > JEDEC_RESERVED_BITS) 95 { 96 cerr << "Can't calculate number of ranks. Invalid data found.\n "; 97 return dimmSize; 98 } 99 logicalRanksPerDimm = (tmp + 1) * dieCount; 100 101 dimmSize = (sdramCap / JEDEC_PRI_BUS_WIDTH_MULTIPLIER) * 102 (priBusWid / sdramWid) * logicalRanksPerDimm; 103 104 return dimmSize; 105 } 106 107 kwdVpdMap memoryVpdParser::readKeywords(Binary::const_iterator iterator) 108 { 109 KeywordVpdMap map{}; 110 111 // collect Dimm size value 112 auto dimmSize = getDimmSize(iterator); 113 if (!dimmSize) 114 { 115 cerr << "Error: Calculated dimm size is 0."; 116 } 117 118 map.emplace("MemorySizeInKB", dimmSize); 119 // point the iterator to DIMM data and skip "11S" 120 advance(iterator, MEMORY_VPD_DATA_START + 3); 121 Binary partNumber(iterator, iterator + PART_NUM_LEN); 122 123 advance(iterator, PART_NUM_LEN); 124 Binary serialNumber(iterator, iterator + SERIAL_NUM_LEN); 125 126 advance(iterator, SERIAL_NUM_LEN); 127 Binary ccin(iterator, iterator + CCIN_LEN); 128 129 map.emplace("FN", partNumber); 130 map.emplace("PN", move(partNumber)); 131 map.emplace("SN", move(serialNumber)); 132 map.emplace("CC", move(ccin)); 133 134 return map; 135 } 136 137 variant<kwdVpdMap, Store> memoryVpdParser::parse() 138 { 139 // Read the data and return the map 140 auto iterator = memVpd.cbegin(); 141 auto vpdDataMap = readKeywords(iterator); 142 143 return vpdDataMap; 144 } 145 146 std::string memoryVpdParser::getInterfaceName() const 147 { 148 return memVpdInf; 149 } 150 151 } // namespace parser 152 } // namespace memory 153 } // namespace vpd 154 } // namespace openpower 155