blob: c7d4a5241932a25f40c871245fa57a1e42106582 [file] [log] [blame]
jinuthomas6555e7e2023-02-14 21:48:00 -06001#include "isdimm_vpd_parser.hpp"
2
3#include <iostream>
4#include <numeric>
5#include <string>
6
7namespace openpower
8{
9namespace vpd
10{
jinuthomas5700b3c2023-03-07 22:51:00 -060011namespace isdimm
jinuthomas6555e7e2023-02-14 21:48:00 -060012{
13namespace parser
14{
15static constexpr auto SPD_JEDEC_DDR4_SDRAM_CAP_MASK = 0x0F;
16static constexpr auto SPD_JEDEC_DDR4_PRI_BUS_WIDTH_MASK = 0x07;
17static constexpr auto SPD_JEDEC_DDR4_SDRAM_WIDTH_MASK = 0x07;
18static constexpr auto SPD_JEDEC_DDR4_NUM_RANKS_MASK = 0x38;
19static constexpr auto SPD_JEDEC_DDR4_DIE_COUNT_MASK = 0x70;
20static constexpr auto SPD_JEDEC_DDR4_SINGLE_LOAD_STACK = 0x02;
21static constexpr auto SPD_JEDEC_DDR4_SIGNAL_LOADING_MASK = 0x03;
22
23static constexpr auto SPD_JEDEC_DDR4_SDRAMCAP_MULTIPLIER = 256;
24static constexpr auto SPD_JEDEC_DDR4_PRI_BUS_WIDTH_MULTIPLIER = 8;
25static constexpr auto SPD_JEDEC_DDR4_SDRAM_WIDTH_MULTIPLIER = 4;
26static constexpr auto SPD_JEDEC_DDR4_SDRAMCAP_RESERVED = 8;
27static constexpr auto SPD_JEDEC_DDR4_4_RESERVED_BITS = 4;
28static constexpr auto SPD_JEDEC_DDR4_3_RESERVED_BITS = 3;
29static constexpr auto SPD_JEDEC_DDR4_DIE_COUNT_RIGHT_SHIFT = 4;
30
31static constexpr auto SPD_JEDEC_DDR4_MFG_ID_MSB_OFFSET = 321;
32static constexpr auto SPD_JEDEC_DDR4_MFG_ID_LSB_OFFSET = 320;
33static constexpr auto SPD_JEDEC_DDR4_SN_BYTE0_OFFSET = 325;
34static constexpr auto SPD_JEDEC_DDR4_SN_BYTE1_OFFSET = 326;
35static constexpr auto SPD_JEDEC_DDR4_SN_BYTE2_OFFSET = 327;
36static constexpr auto SPD_JEDEC_DDR4_SN_BYTE3_OFFSET = 328;
37static constexpr auto SPD_JEDEC_DDR4_SDRAM_DENSITY_BANK_OFFSET = 4;
38static constexpr auto SPD_JEDEC_DDR4_SDRAM_ADDR_OFFSET = 5;
39static constexpr auto SPD_JEDEC_DDR4_DRAM_PRI_PACKAGE_OFFSET = 6;
40static constexpr auto SPD_JEDEC_DDR4_DRAM_MODULE_ORG_OFFSET = 12;
41
42// DDR5 JEDEC specification constants
43static constexpr auto SPD_JEDEC_DDR5_SUB_CHANNELS_PER_DIMM = 235;
44static constexpr auto SPD_JEDEC_DDR5_SUB_CHANNELS_PER_DIMM_MASK = 0x60;
45static constexpr auto SPD_JEDEC_DDR5_PRI_BUS_WIDTH_PER_CHANNEL = 235;
46static constexpr auto SPD_JEDEC_DDR5_PRI_BUS_WIDTH_PER_CHANNEL_MASK = 0x07;
47static constexpr auto SPD_JEDEC_DDR5_SDRAM_IO_WIDTH_SYM_ALL = 6;
48static constexpr auto SPD_JEDEC_DDR5_SDRAM_IO_WIDTH_ASYM_EVEN = 6;
49static constexpr auto SPD_JEDEC_DDR5_SDRAM_IO_WIDTH_ASYM_ODD = 10;
50static constexpr auto SPD_JEDEC_DDR5_SDRAM_IO_WIDTH_MASK = 0xE0;
51static constexpr auto SPD_JEDEC_DDR5_DIE_PER_PKG_SYM_ALL = 4;
52static constexpr auto SPD_JEDEC_DDR5_DIE_PER_PKG_ASYM_EVEN = 4;
53static constexpr auto SPD_JEDEC_DDR5_DIE_PER_PKG_ASYM_ODD = 8;
54static constexpr auto SPD_JEDEC_DDR5_DIE_PER_PKG_MASK = 0xE0;
55static constexpr auto SPD_JEDEC_DDR5_SDRAM_DENSITY_PER_DIE_SYM_ALL = 4;
56static constexpr auto SPD_JEDEC_DDR5_SDRAM_DENSITY_PER_DIE_ASYM_EVEN = 4;
57static constexpr auto SPD_JEDEC_DDR5_SDRAM_DENSITY_PER_DIE_ASYM_ODD = 8;
58static constexpr auto SPD_JEDEC_DDR5_SDRAM_DENSITY_PER_DIE_MASK = 0x1F;
59static constexpr auto SPD_JEDEC_DDR5_RANK_MIX = 234;
60static constexpr auto SPD_JEDEC_DDR5_RANK_MIX_SYMMETRICAL_MASK = 0x40;
61
62auto isdimmVpdParser::getDDR4DimmCapacity(Binary::const_iterator& iterator)
63{
64 size_t tmp = 0, dimmSize = 0;
65
66 size_t sdramCap = 1, priBusWid = 1, sdramWid = 1, logicalRanksPerDimm = 1;
67 Byte dieCount = 1;
68
69 // NOTE: This calculation is Only for DDR4
70
71 // Calculate SDRAM capacity
72 tmp = iterator[constants::SPD_BYTE_4] & SPD_JEDEC_DDR4_SDRAM_CAP_MASK;
73 /* Make sure the bits are not Reserved */
74 if (tmp >= SPD_JEDEC_DDR4_SDRAMCAP_RESERVED)
75 {
76 std::cerr
77 << "Bad data in spd byte 4. Can't calculate SDRAM capacity and so "
78 "dimm size.\n ";
79 return dimmSize;
80 }
81
82 sdramCap = (sdramCap << tmp) * SPD_JEDEC_DDR4_SDRAMCAP_MULTIPLIER;
83
84 /* Calculate Primary bus width */
85 tmp = iterator[constants::SPD_BYTE_13] & SPD_JEDEC_DDR4_PRI_BUS_WIDTH_MASK;
86 if (tmp >= SPD_JEDEC_DDR4_4_RESERVED_BITS)
87 {
88 std::cerr
89 << "Bad data in spd byte 13. Can't calculate primary bus width "
90 "and so dimm size.\n ";
91 return dimmSize;
92 }
93 priBusWid = (priBusWid << tmp) * SPD_JEDEC_DDR4_PRI_BUS_WIDTH_MULTIPLIER;
94
95 /* Calculate SDRAM width */
96 tmp = iterator[constants::SPD_BYTE_12] & SPD_JEDEC_DDR4_SDRAM_WIDTH_MASK;
97 if (tmp >= SPD_JEDEC_DDR4_4_RESERVED_BITS)
98 {
99 std::cerr
100 << "Bad data in vpd byte 12. Can't calculate SDRAM width and so "
101 "dimm size.\n ";
102 return dimmSize;
103 }
104 sdramWid = (sdramWid << tmp) * SPD_JEDEC_DDR4_SDRAM_WIDTH_MULTIPLIER;
105
106 tmp = iterator[constants::SPD_BYTE_6] & SPD_JEDEC_DDR4_SIGNAL_LOADING_MASK;
107
108 if (tmp == SPD_JEDEC_DDR4_SINGLE_LOAD_STACK)
109 {
110 // Fetch die count
111 tmp = iterator[constants::SPD_BYTE_6] & SPD_JEDEC_DDR4_DIE_COUNT_MASK;
112 tmp >>= SPD_JEDEC_DDR4_DIE_COUNT_RIGHT_SHIFT;
113 dieCount = tmp + 1;
114 }
115
116 /* Calculate Number of ranks */
117 tmp = iterator[constants::SPD_BYTE_12] & SPD_JEDEC_DDR4_NUM_RANKS_MASK;
118 tmp >>= SPD_JEDEC_DDR4_3_RESERVED_BITS;
119
120 if (tmp >= SPD_JEDEC_DDR4_4_RESERVED_BITS)
121 {
122 std::cerr << "Can't calculate number of ranks. Invalid data found.\n ";
123 return dimmSize;
124 }
125 logicalRanksPerDimm = (tmp + 1) * dieCount;
126
127 dimmSize = (sdramCap / SPD_JEDEC_DDR4_PRI_BUS_WIDTH_MULTIPLIER) *
128 (priBusWid / sdramWid) * logicalRanksPerDimm;
129
130 return dimmSize;
131}
132
133auto isdimmVpdParser::getDDR4PartNumber(Binary::const_iterator& iterator)
134{
135
136 char tmpPN[constants::PART_NUM_LEN + 1] = {'\0'};
137 sprintf(tmpPN, "%02X%02X%02X%X",
138 iterator[SPD_JEDEC_DDR4_SDRAM_DENSITY_BANK_OFFSET],
139 iterator[SPD_JEDEC_DDR4_SDRAM_ADDR_OFFSET],
140 iterator[SPD_JEDEC_DDR4_DRAM_PRI_PACKAGE_OFFSET],
141 iterator[SPD_JEDEC_DDR4_DRAM_MODULE_ORG_OFFSET] & 0x0F);
142 std::string partNumber(tmpPN, sizeof(tmpPN));
143 return partNumber;
144}
145
146auto isdimmVpdParser::getDDR4SerialNumber(Binary::const_iterator& iterator)
147{
148 char tmpSN[constants::SERIAL_NUM_LEN + 1] = {'\0'};
149 sprintf(tmpSN, "%02X%02X%02X%02X%02X%02X",
150 iterator[SPD_JEDEC_DDR4_MFG_ID_MSB_OFFSET],
151 iterator[SPD_JEDEC_DDR4_MFG_ID_LSB_OFFSET],
152 iterator[SPD_JEDEC_DDR4_SN_BYTE0_OFFSET],
153 iterator[SPD_JEDEC_DDR4_SN_BYTE1_OFFSET],
154 iterator[SPD_JEDEC_DDR4_SN_BYTE2_OFFSET],
155 iterator[SPD_JEDEC_DDR4_SN_BYTE3_OFFSET]);
156 std::string serialNumber(tmpSN, sizeof(tmpSN));
157 return serialNumber;
158}
159
160auto isdimmVpdParser::getDDR4FruNumber(const std::string& partNumber)
161{
162 // check for 128GB ISRDIMM not implemented
163 //(128GB 2RX4(8GX72) IS RDIMM 36*(16GBIT, 2H),1.2V 288PIN,1.2" ROHS) - NA
164
165 static std::unordered_map<std::string, std::string> pnFruMap = {
166 {"8421000", "78P4191"}, {"8421008", "78P4192"}, {"8529000", "78P4197"},
167 {"8529008", "78P4198"}, {"8529928", "78P4199"}, {"8529B28", "78P4200"},
168 {"8631008", "78P6815"}, {"8631928", "78P6925"}};
169
170 std::string fruNumber;
171 auto itr = pnFruMap.find(partNumber);
172 if (itr != pnFruMap.end())
173 {
174 fruNumber = itr->second;
175 }
176 else
177 {
178 fruNumber = "FFFFFFF";
179 }
180 return fruNumber;
181}
182
183auto isdimmVpdParser::getDDR4CCIN(const std::string& partNumber)
184{
185 static std::unordered_map<std::string, std::string> pnCCINMap = {
186 {"8421000", "324D"}, {"8421008", "324E"}, {"8529000", "324E"},
187 {"8529008", "324F"}, {"8529928", "325A"}, {"8529B28", "324C"},
188 {"8631008", "32BB"}, {"8631928", "32BC"}};
189
190 std::string ccin;
191 auto itr = pnCCINMap.find(partNumber);
192 if (itr != pnCCINMap.end())
193 {
194 ccin = itr->second;
195 }
196 else
197 {
198 ccin = "XXXX";
199 }
200 return ccin;
201}
202
203auto isdimmVpdParser::getDDR5DimmCapacity(Binary::const_iterator& iterator)
204{
205 // dummy implementation to be updated when required
206 size_t dimmSize = 0;
207 (void)iterator;
208 return dimmSize;
209}
210
211auto isdimmVpdParser::getDDR5PartNumber(Binary::const_iterator& iterator)
212{
213 // dummy implementation to be updated when required
214 std::string partNumber;
215 (void)iterator;
216 partNumber = "0123456";
217 return partNumber;
218}
219
220auto isdimmVpdParser::getDDR5SerialNumber(Binary::const_iterator& iterator)
221{
222 // dummy implementation to be updated when required
223 std::string serialNumber;
224 (void)iterator;
225 serialNumber = "444444444444";
226 return serialNumber;
227}
228
229auto isdimmVpdParser::getDDR5FruNumber(const std::string& partNumber)
230{
231 // dummy implementation to be updated when required
232 static std::unordered_map<std::string, std::string> pnFruMap = {
233 {"1234567", "XXXXXXX"}};
234
235 std::string fruNumber;
236 auto itr = pnFruMap.find(partNumber);
237 if (itr != pnFruMap.end())
238 {
239 fruNumber = itr->second;
240 }
241 else
242 {
243 fruNumber = "FFFFFFF";
244 }
245 return fruNumber;
246}
247
248auto isdimmVpdParser::getDDR5CCIN(const std::string& partNumber)
249{
250 // dummy implementation to be updated when required
251 static std::unordered_map<std::string, std::string> pnCCINMap = {
252 {"1234567", "XXXX"}};
253
254 std::string ccin;
255 auto itr = pnCCINMap.find(partNumber);
256 if (itr != pnCCINMap.end())
257 {
258 ccin = itr->second;
259 }
260 else
261 {
262 ccin = "XXXX";
263 }
264 return ccin;
265}
266
267kwdVpdMap isdimmVpdParser::readKeywords(Binary::const_iterator& iterator)
268{
269 inventory::KeywordVpdMap keywordValueMap{};
270 if ((iterator[constants::SPD_BYTE_2] & constants::SPD_BYTE_MASK) ==
271 constants::SPD_DRAM_TYPE_DDR5)
272 {
273 auto dimmSize = getDDR5DimmCapacity(iterator);
274 if (!dimmSize)
275 {
276 std::cerr << "Error: Calculated dimm size is 0.";
277 }
278 else if (dimmSize < constants::CONVERT_MB_TO_KB)
279 {
280 keywordValueMap.emplace("MemorySizeInMB", dimmSize);
281 }
282 else
283 {
284 size_t dimmCapacityInGB = dimmSize / constants::CONVERT_MB_TO_KB;
285 keywordValueMap.emplace("MemorySizeInGB", dimmCapacityInGB);
286 }
287 auto partNumber = getDDR5PartNumber(iterator);
288 keywordValueMap.emplace("PN", move(partNumber));
289 auto fruNumber = getDDR5FruNumber(partNumber);
290 keywordValueMap.emplace("FN", move(fruNumber));
291 auto serialNumber = getDDR5SerialNumber(iterator);
292 keywordValueMap.emplace("SN", move(serialNumber));
293 auto ccin = getDDR5CCIN(partNumber);
294 keywordValueMap.emplace("CC", move(ccin));
295 }
296 else if ((iterator[constants::SPD_BYTE_2] & constants::SPD_BYTE_MASK) ==
297 constants::SPD_DRAM_TYPE_DDR4)
298 {
299 auto dimmSize = getDDR4DimmCapacity(iterator);
300 if (!dimmSize)
301 {
302 std::cerr << "Error: Calculated dimm size is 0.";
303 }
304 else if (dimmSize < constants::CONVERT_MB_TO_KB)
305 {
306 keywordValueMap.emplace("MemorySizeInMB", dimmSize);
307 }
308 else
309 {
310 size_t dimmCapacityInGB = dimmSize / constants::CONVERT_MB_TO_KB;
311 keywordValueMap.emplace("MemorySizeInGB", dimmCapacityInGB);
312 }
313 size_t dimmCapacityInGB = dimmSize / constants::CONVERT_MB_TO_KB;
314 keywordValueMap.emplace("MemorySizeInGB", dimmCapacityInGB);
315 auto partNumber = getDDR4PartNumber(iterator);
316 keywordValueMap.emplace("PN", move(partNumber));
317 auto fruNumber = getDDR4FruNumber(partNumber);
318 keywordValueMap.emplace("FN", move(fruNumber));
319 auto serialNumber = getDDR4SerialNumber(iterator);
320 keywordValueMap.emplace("SN", move(serialNumber));
321 auto ccin = getDDR4CCIN(partNumber);
322 keywordValueMap.emplace("CC", move(ccin));
323 }
324 return keywordValueMap;
325}
326
327std::variant<kwdVpdMap, Store> isdimmVpdParser::parse()
328{
329 // Read the data and return the map
330 auto iterator = memVpd.cbegin();
331 auto vpdDataMap = readKeywords(iterator);
332
333 return vpdDataMap;
334}
335
336} // namespace parser
jinuthomas5700b3c2023-03-07 22:51:00 -0600337} // namespace isdimm
jinuthomas6555e7e2023-02-14 21:48:00 -0600338} // namespace vpd
jinuthomas5700b3c2023-03-07 22:51:00 -0600339} // namespace openpower