blob: 7071516f0cdfac23d38365762d10051d2fc3bf91 [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{
jinuthomas6555e7e2023-02-14 21:48:00 -0600135 char tmpPN[constants::PART_NUM_LEN + 1] = {'\0'};
136 sprintf(tmpPN, "%02X%02X%02X%X",
137 iterator[SPD_JEDEC_DDR4_SDRAM_DENSITY_BANK_OFFSET],
138 iterator[SPD_JEDEC_DDR4_SDRAM_ADDR_OFFSET],
139 iterator[SPD_JEDEC_DDR4_DRAM_PRI_PACKAGE_OFFSET],
140 iterator[SPD_JEDEC_DDR4_DRAM_MODULE_ORG_OFFSET] & 0x0F);
jinuthomasd640f692023-03-28 04:13:23 -0500141 std::string partNumber(tmpPN, sizeof(tmpPN) - 1);
jinuthomas6555e7e2023-02-14 21:48:00 -0600142 return partNumber;
143}
144
145auto isdimmVpdParser::getDDR4SerialNumber(Binary::const_iterator& iterator)
146{
147 char tmpSN[constants::SERIAL_NUM_LEN + 1] = {'\0'};
148 sprintf(tmpSN, "%02X%02X%02X%02X%02X%02X",
149 iterator[SPD_JEDEC_DDR4_MFG_ID_MSB_OFFSET],
150 iterator[SPD_JEDEC_DDR4_MFG_ID_LSB_OFFSET],
151 iterator[SPD_JEDEC_DDR4_SN_BYTE0_OFFSET],
152 iterator[SPD_JEDEC_DDR4_SN_BYTE1_OFFSET],
153 iterator[SPD_JEDEC_DDR4_SN_BYTE2_OFFSET],
154 iterator[SPD_JEDEC_DDR4_SN_BYTE3_OFFSET]);
jinuthomasd640f692023-03-28 04:13:23 -0500155 std::string serialNumber(tmpSN, sizeof(tmpSN) - 1);
jinuthomas6555e7e2023-02-14 21:48:00 -0600156 return serialNumber;
157}
158
159auto isdimmVpdParser::getDDR4FruNumber(const std::string& partNumber)
160{
161 // check for 128GB ISRDIMM not implemented
162 //(128GB 2RX4(8GX72) IS RDIMM 36*(16GBIT, 2H),1.2V 288PIN,1.2" ROHS) - NA
163
164 static std::unordered_map<std::string, std::string> pnFruMap = {
165 {"8421000", "78P4191"}, {"8421008", "78P4192"}, {"8529000", "78P4197"},
166 {"8529008", "78P4198"}, {"8529928", "78P4199"}, {"8529B28", "78P4200"},
167 {"8631008", "78P6815"}, {"8631928", "78P6925"}};
168
169 std::string fruNumber;
170 auto itr = pnFruMap.find(partNumber);
171 if (itr != pnFruMap.end())
172 {
173 fruNumber = itr->second;
174 }
175 else
176 {
177 fruNumber = "FFFFFFF";
178 }
179 return fruNumber;
180}
181
182auto isdimmVpdParser::getDDR4CCIN(const std::string& partNumber)
183{
184 static std::unordered_map<std::string, std::string> pnCCINMap = {
185 {"8421000", "324D"}, {"8421008", "324E"}, {"8529000", "324E"},
186 {"8529008", "324F"}, {"8529928", "325A"}, {"8529B28", "324C"},
187 {"8631008", "32BB"}, {"8631928", "32BC"}};
188
189 std::string ccin;
190 auto itr = pnCCINMap.find(partNumber);
191 if (itr != pnCCINMap.end())
192 {
193 ccin = itr->second;
194 }
195 else
196 {
197 ccin = "XXXX";
198 }
199 return ccin;
200}
201
202auto isdimmVpdParser::getDDR5DimmCapacity(Binary::const_iterator& iterator)
203{
204 // dummy implementation to be updated when required
205 size_t dimmSize = 0;
206 (void)iterator;
207 return dimmSize;
208}
209
210auto isdimmVpdParser::getDDR5PartNumber(Binary::const_iterator& iterator)
211{
212 // dummy implementation to be updated when required
213 std::string partNumber;
214 (void)iterator;
215 partNumber = "0123456";
216 return partNumber;
217}
218
219auto isdimmVpdParser::getDDR5SerialNumber(Binary::const_iterator& iterator)
220{
221 // dummy implementation to be updated when required
222 std::string serialNumber;
223 (void)iterator;
224 serialNumber = "444444444444";
225 return serialNumber;
226}
227
228auto isdimmVpdParser::getDDR5FruNumber(const std::string& partNumber)
229{
230 // dummy implementation to be updated when required
231 static std::unordered_map<std::string, std::string> pnFruMap = {
232 {"1234567", "XXXXXXX"}};
233
234 std::string fruNumber;
235 auto itr = pnFruMap.find(partNumber);
236 if (itr != pnFruMap.end())
237 {
238 fruNumber = itr->second;
239 }
240 else
241 {
242 fruNumber = "FFFFFFF";
243 }
244 return fruNumber;
245}
246
247auto isdimmVpdParser::getDDR5CCIN(const std::string& partNumber)
248{
249 // dummy implementation to be updated when required
250 static std::unordered_map<std::string, std::string> pnCCINMap = {
251 {"1234567", "XXXX"}};
252
253 std::string ccin;
254 auto itr = pnCCINMap.find(partNumber);
255 if (itr != pnCCINMap.end())
256 {
257 ccin = itr->second;
258 }
259 else
260 {
261 ccin = "XXXX";
262 }
263 return ccin;
264}
265
266kwdVpdMap isdimmVpdParser::readKeywords(Binary::const_iterator& iterator)
267{
268 inventory::KeywordVpdMap keywordValueMap{};
269 if ((iterator[constants::SPD_BYTE_2] & constants::SPD_BYTE_MASK) ==
270 constants::SPD_DRAM_TYPE_DDR5)
271 {
jinuthomasd640f692023-03-28 04:13:23 -0500272 size_t dimmSize = getDDR5DimmCapacity(iterator);
jinuthomas6555e7e2023-02-14 21:48:00 -0600273 if (!dimmSize)
274 {
275 std::cerr << "Error: Calculated dimm size is 0.";
276 }
jinuthomas6555e7e2023-02-14 21:48:00 -0600277 else
278 {
jinuthomasd640f692023-03-28 04:13:23 -0500279 keywordValueMap.emplace("MemorySizeInKB", dimmSize);
jinuthomas6555e7e2023-02-14 21:48:00 -0600280 }
281 auto partNumber = getDDR5PartNumber(iterator);
jinuthomas6555e7e2023-02-14 21:48:00 -0600282 auto fruNumber = getDDR5FruNumber(partNumber);
283 keywordValueMap.emplace("FN", move(fruNumber));
284 auto serialNumber = getDDR5SerialNumber(iterator);
285 keywordValueMap.emplace("SN", move(serialNumber));
286 auto ccin = getDDR5CCIN(partNumber);
287 keywordValueMap.emplace("CC", move(ccin));
jinuthomasd640f692023-03-28 04:13:23 -0500288 keywordValueMap.emplace("PN", move(partNumber));
jinuthomas6555e7e2023-02-14 21:48:00 -0600289 }
290 else if ((iterator[constants::SPD_BYTE_2] & constants::SPD_BYTE_MASK) ==
291 constants::SPD_DRAM_TYPE_DDR4)
292 {
jinuthomasd640f692023-03-28 04:13:23 -0500293 size_t dimmSize = getDDR4DimmCapacity(iterator);
jinuthomas6555e7e2023-02-14 21:48:00 -0600294 if (!dimmSize)
295 {
296 std::cerr << "Error: Calculated dimm size is 0.";
297 }
jinuthomas6555e7e2023-02-14 21:48:00 -0600298 else
299 {
jinuthomasd640f692023-03-28 04:13:23 -0500300 keywordValueMap.emplace("MemorySizeInKB",
301 (dimmSize * constants::CONVERT_MB_TO_KB));
jinuthomas6555e7e2023-02-14 21:48:00 -0600302 }
jinuthomasd640f692023-03-28 04:13:23 -0500303
jinuthomas6555e7e2023-02-14 21:48:00 -0600304 auto partNumber = getDDR4PartNumber(iterator);
jinuthomas6555e7e2023-02-14 21:48:00 -0600305 auto fruNumber = getDDR4FruNumber(partNumber);
jinuthomas6555e7e2023-02-14 21:48:00 -0600306 auto serialNumber = getDDR4SerialNumber(iterator);
jinuthomas6555e7e2023-02-14 21:48:00 -0600307 auto ccin = getDDR4CCIN(partNumber);
jinuthomasd640f692023-03-28 04:13:23 -0500308 keywordValueMap.emplace("PN", move(partNumber));
309 keywordValueMap.emplace("FN", move(fruNumber));
310 keywordValueMap.emplace("SN", move(serialNumber));
jinuthomas6555e7e2023-02-14 21:48:00 -0600311 keywordValueMap.emplace("CC", move(ccin));
312 }
313 return keywordValueMap;
314}
315
316std::variant<kwdVpdMap, Store> isdimmVpdParser::parse()
317{
318 // Read the data and return the map
319 auto iterator = memVpd.cbegin();
320 auto vpdDataMap = readKeywords(iterator);
321
322 return vpdDataMap;
323}
324
325} // namespace parser
jinuthomas5700b3c2023-03-07 22:51:00 -0600326} // namespace isdimm
jinuthomas6555e7e2023-02-14 21:48:00 -0600327} // namespace vpd
jinuthomas5700b3c2023-03-07 22:51:00 -0600328} // namespace openpower