blob: 4a0ac7c67ac3f4ce4392bee0b3f08e7e7864191e [file] [log] [blame]
Alpana Kumaria00936f2020-04-14 07:15:46 -05001#include "memory_vpd_parser.hpp"
2
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +05303#include <cmath>
4#include <cstdint>
Alpana Kumaria00936f2020-04-14 07:15:46 -05005#include <iostream>
6#include <numeric>
7#include <string>
8
9namespace openpower
10{
11namespace vpd
12{
13namespace memory
14{
15namespace parser
16{
17using namespace inventory;
Alpana Kumaria00936f2020-04-14 07:15:46 -050018using namespace constants;
19using namespace std;
SunnySrivastava1984e12b1812020-05-26 02:23:11 -050020using namespace openpower::vpd::parser;
Alpana Kumaria00936f2020-04-14 07:15:46 -050021
Alpana Kumari3ab26a72021-04-05 19:09:19 +000022static constexpr auto JEDEC_SDRAM_CAP_MASK = 0x0F;
23static constexpr auto JEDEC_PRI_BUS_WIDTH_MASK = 0x07;
24static constexpr auto JEDEC_SDRAM_WIDTH_MASK = 0x07;
25static constexpr auto JEDEC_NUM_RANKS_MASK = 0x38;
26static constexpr auto JEDEC_DIE_COUNT_MASK = 0x70;
27static constexpr auto JEDEC_SINGLE_LOAD_STACK = 0x02;
28static constexpr auto JEDEC_SIGNAL_LOADING_MASK = 0x03;
29
30static constexpr auto JEDEC_SDRAMCAP_MULTIPLIER = 256;
31static constexpr auto JEDEC_PRI_BUS_WIDTH_MULTIPLIER = 8;
32static constexpr auto JEDEC_SDRAM_WIDTH_MULTIPLIER = 4;
33static constexpr auto JEDEC_SDRAMCAP_RESERVED = 6;
34static constexpr auto JEDEC_RESERVED_BITS = 3;
35static constexpr auto JEDEC_DIE_COUNT_RIGHT_SHIFT = 4;
36
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +053037static constexpr auto SDRAM_DENSITY_PER_DIE_24GB = 24;
38static constexpr auto SDRAM_DENSITY_PER_DIE_32GB = 32;
39static constexpr auto SDRAM_DENSITY_PER_DIE_48GB = 48;
40static constexpr auto SDRAM_DENSITY_PER_DIE_64GB = 64;
41static constexpr auto SDRAM_DENSITY_PER_DIE_UNDEFINED = 0;
42
43static constexpr auto PRIMARY_BUS_WIDTH_32_BITS = 32;
44static constexpr auto PRIMARY_BUS_WIDTH_UNUSED = 0;
Sunny Srivastava172e74f2024-05-21 02:02:05 -050045static constexpr auto DRAM_MANUFACTURER_ID_OFFSET = 0x228;
46static constexpr auto DRAM_MANUFACTURER_ID_LENGTH = 0x02;
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +053047
48bool memoryVpdParser::checkValidValue(uint8_t l_ByteValue, uint8_t shift,
49 uint8_t minValue, uint8_t maxValue)
50{
51 l_ByteValue = l_ByteValue >> shift;
52 if ((l_ByteValue > maxValue) || (l_ByteValue < minValue))
53 {
54 cout << "Non valid Value encountered value[" << l_ByteValue
55 << "] range [" << minValue << ".." << maxValue << "] found "
56 << " " << endl;
57 return false;
58 }
59 else
60 {
61 return true;
62 }
63}
64
65uint8_t memoryVpdParser::getDDR5DensityPerDie(uint8_t l_ByteValue)
66{
67 uint8_t l_densityPerDie = SDRAM_DENSITY_PER_DIE_UNDEFINED;
68 if (l_ByteValue < constants::VALUE_5)
69 {
70 l_densityPerDie = l_ByteValue * constants::VALUE_4;
71 }
72 else
73 {
74 switch (l_ByteValue)
75 {
76 case VALUE_5:
77 l_densityPerDie = SDRAM_DENSITY_PER_DIE_24GB;
78 break;
79
80 case VALUE_6:
81 l_densityPerDie = SDRAM_DENSITY_PER_DIE_32GB;
82 break;
83
84 case VALUE_7:
85 l_densityPerDie = SDRAM_DENSITY_PER_DIE_48GB;
86 break;
87
88 case VALUE_8:
89 l_densityPerDie = SDRAM_DENSITY_PER_DIE_64GB;
90 break;
91
92 default:
93 cout << "default value encountered for density per die" << endl;
94 l_densityPerDie = SDRAM_DENSITY_PER_DIE_UNDEFINED;
95 break;
96 }
97 }
98 return l_densityPerDie;
99}
100
101uint8_t memoryVpdParser::getDDR5DiePerPackage(uint8_t l_ByteValue)
102{
103 uint8_t l_DiePerPackage = constants::VALUE_0;
104 if (l_ByteValue < constants::VALUE_2)
105 {
106 l_DiePerPackage = l_ByteValue + constants::VALUE_1;
107 }
108 else
109 {
Patrick Williams08dc31c2024-08-16 15:21:06 -0400110 l_DiePerPackage =
111 pow(constants::VALUE_2, (l_ByteValue - constants::VALUE_1));
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530112 }
113 return l_DiePerPackage;
114}
115
116auto memoryVpdParser::getDdr5BasedDDimmSize(Binary::const_iterator iterator)
117{
118 size_t dimmSize = 0;
119
120 do
121 {
122 if (!checkValidValue(iterator[constants::SPD_BYTE_235] &
123 constants::MASK_BYTE_BITS_01,
124 constants::SHIFT_BITS_0, constants::VALUE_1,
125 constants::VALUE_3) ||
126 !checkValidValue(iterator[constants::SPD_BYTE_235] &
127 constants::MASK_BYTE_BITS_345,
128 constants::SHIFT_BITS_3, constants::VALUE_1,
129 constants::VALUE_3))
130 {
131 std::cerr
Jinu Joy Thomasd7a6dec2024-02-19 01:10:29 -0600132 << "Capacity calculation failed for channels per DIMM. DDIMM "
133 "Byte 235 value ["
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530134 << iterator[constants::SPD_BYTE_235] << "]";
135 break;
136 }
Jinu Joy Thomasd7a6dec2024-02-19 01:10:29 -0600137 uint8_t l_channelsPerPhy =
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530138 (((iterator[constants::SPD_BYTE_235] & constants::MASK_BYTE_BITS_01)
139 ? constants::VALUE_1
140 : constants::VALUE_0) +
141 ((iterator[constants::SPD_BYTE_235] &
142 constants::MASK_BYTE_BITS_345)
143 ? constants::VALUE_1
144 : constants::VALUE_0));
145
Patrick Williams08dc31c2024-08-16 15:21:06 -0400146 uint8_t l_channelsPerDdimm =
147 (((iterator[constants::SPD_BYTE_235] &
148 constants::MASK_BYTE_BITS_6) >>
149 constants::VALUE_6) +
150 ((iterator[constants::SPD_BYTE_235] &
151 constants::MASK_BYTE_BITS_7) >>
152 constants::VALUE_7)) *
153 l_channelsPerPhy;
Jinu Joy Thomasd7a6dec2024-02-19 01:10:29 -0600154
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530155 if (!checkValidValue(iterator[constants::SPD_BYTE_235] &
156 constants::MASK_BYTE_BITS_012,
157 constants::SHIFT_BITS_0, constants::VALUE_1,
158 constants::VALUE_3))
159 {
160 std::cerr
Jinu Joy Thomasd7a6dec2024-02-19 01:10:29 -0600161 << "Capacity calculation failed for bus width per channel. "
162 "DDIMM Byte 235 value ["
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530163 << iterator[constants::SPD_BYTE_235] << "]";
164 break;
165 }
166 uint8_t l_busWidthPerChannel =
167 (iterator[constants::SPD_BYTE_235] & constants::MASK_BYTE_BITS_012)
168 ? PRIMARY_BUS_WIDTH_32_BITS
169 : PRIMARY_BUS_WIDTH_UNUSED;
170
Patrick Williams08dc31c2024-08-16 15:21:06 -0400171 if (!checkValidValue(
172 iterator[constants::SPD_BYTE_4] & constants::MASK_BYTE_BITS_567,
173 constants::SHIFT_BITS_5, constants::VALUE_0,
174 constants::VALUE_5))
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530175 {
176 std::cerr
Jinu Joy Thomasd7a6dec2024-02-19 01:10:29 -0600177 << "Capacity calculation failed for die per package. DDIMM "
178 "Byte 4 value ["
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530179 << iterator[constants::SPD_BYTE_4] << "]";
180 break;
181 }
182 uint8_t l_diePerPackage = getDDR5DiePerPackage(
183 (iterator[constants::SPD_BYTE_4] & constants::MASK_BYTE_BITS_567) >>
184 constants::VALUE_5);
185
186 if (!checkValidValue(iterator[constants::SPD_BYTE_4] &
187 constants::MASK_BYTE_BITS_01234,
188 constants::SHIFT_BITS_0, constants::VALUE_1,
189 constants::VALUE_8))
190 {
191 std::cerr
Jinu Joy Thomasd7a6dec2024-02-19 01:10:29 -0600192 << "Capacity calculation failed for SDRAM Density per Die. "
193 "DDIMM Byte 4 value ["
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530194 << iterator[constants::SPD_BYTE_4] << "]";
195 break;
196 }
197 uint8_t l_densityPerDie = getDDR5DensityPerDie(
198 iterator[constants::SPD_BYTE_4] & constants::MASK_BYTE_BITS_01234);
199
Jinu Joy Thomasd7a6dec2024-02-19 01:10:29 -0600200 uint8_t l_ranksPerChannel = 0;
201 if (((iterator[constants::SPD_BYTE_235] &
202 constants::MASK_BYTE_BITS_7) >>
203 constants::VALUE_7))
204 {
205 l_ranksPerChannel = ((iterator[constants::SPD_BYTE_234] &
206 constants::MASK_BYTE_BITS_345) >>
207 constants::VALUE_3) +
208 constants::VALUE_1;
209 }
210 else if (((iterator[constants::SPD_BYTE_235] &
211 constants::MASK_BYTE_BITS_6) >>
212 constants::VALUE_6))
213 {
214 l_ranksPerChannel = (iterator[constants::SPD_BYTE_234] &
215 constants::MASK_BYTE_BITS_012) +
216 constants::VALUE_1;
217 }
218#if 0
219 // Old Style capacity calculation kept for reference
220 // will be removed later
221 uint8_t l_ranksPerChannel =
222 (((iterator[constants::SPD_BYTE_234] &
223 constants::MASK_BYTE_BITS_345) >>
224 constants::VALUE_3) *
225 ((iterator[constants::SPD_BYTE_235] &
226 constants::MASK_BYTE_BITS_7) >>
227 constants::VALUE_7)) +
228 ((iterator[constants::SPD_BYTE_234] &
229 constants::MASK_BYTE_BITS_012) +
230 constants::VALUE_2 * ((iterator[constants::SPD_BYTE_235] &
231 constants::MASK_BYTE_BITS_6) >>
232 constants::VALUE_6));
233#endif
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530234
Patrick Williams08dc31c2024-08-16 15:21:06 -0400235 if (!checkValidValue(
236 iterator[constants::SPD_BYTE_6] & constants::MASK_BYTE_BITS_567,
237 constants::SHIFT_BITS_5, constants::VALUE_0,
238 constants::VALUE_3))
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530239 {
240 std::cout
241 << "Capacity calculation failed for dram width DDIMM Byte 6 value ["
242 << iterator[constants::SPD_BYTE_6] << "]";
243 break;
244 }
Patrick Williams08dc31c2024-08-16 15:21:06 -0400245 uint8_t l_dramWidth =
246 VALUE_4 * (VALUE_1 << ((iterator[constants::SPD_BYTE_6] &
247 constants::MASK_BYTE_BITS_567) >>
248 constants::VALUE_5));
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530249
Jinu Joy Thomasd7a6dec2024-02-19 01:10:29 -0600250 dimmSize = (l_channelsPerDdimm * l_busWidthPerChannel *
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530251 l_diePerPackage * l_densityPerDie * l_ranksPerChannel) /
252 (8 * l_dramWidth);
253
jinuthomas777f3492023-10-10 06:17:14 -0500254 } while (false);
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530255
Jinu Joy Thomas60c68e02024-02-05 22:07:32 -0600256 return constants::CONVERT_GB_TO_KB * dimmSize;
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530257}
258
259auto memoryVpdParser::getDdr4BasedDDimmSize(Binary::const_iterator iterator)
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000260{
261 size_t tmp = 0, dimmSize = 0;
262
263 size_t sdramCap = 1, priBusWid = 1, sdramWid = 1, logicalRanksPerDimm = 1;
264 Byte dieCount = 1;
265
266 // NOTE: This calculation is Only for DDR4
267
268 // Calculate SDRAM capacity
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530269 tmp = iterator[SPD_BYTE_4] & JEDEC_SDRAM_CAP_MASK;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000270 /* Make sure the bits are not Reserved */
271 if (tmp > JEDEC_SDRAMCAP_RESERVED)
272 {
273 cerr << "Bad data in vpd byte 4. Can't calculate SDRAM capacity and so "
274 "dimm size.\n ";
275 return dimmSize;
276 }
277
278 sdramCap = (sdramCap << tmp) * JEDEC_SDRAMCAP_MULTIPLIER;
279
280 /* Calculate Primary bus width */
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530281 tmp = iterator[SPD_BYTE_13] & JEDEC_PRI_BUS_WIDTH_MASK;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000282 if (tmp > JEDEC_RESERVED_BITS)
283 {
284 cerr << "Bad data in vpd byte 13. Can't calculate primary bus width "
285 "and so dimm size.\n ";
286 return dimmSize;
287 }
288 priBusWid = (priBusWid << tmp) * JEDEC_PRI_BUS_WIDTH_MULTIPLIER;
289
290 /* Calculate SDRAM width */
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530291 tmp = iterator[SPD_BYTE_12] & JEDEC_SDRAM_WIDTH_MASK;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000292 if (tmp > JEDEC_RESERVED_BITS)
293 {
294 cerr << "Bad data in vpd byte 12. Can't calculate SDRAM width and so "
295 "dimm size.\n ";
296 return dimmSize;
297 }
298 sdramWid = (sdramWid << tmp) * JEDEC_SDRAM_WIDTH_MULTIPLIER;
299
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530300 tmp = iterator[SPD_BYTE_6] & JEDEC_SIGNAL_LOADING_MASK;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000301
302 if (tmp == JEDEC_SINGLE_LOAD_STACK)
303 {
304 // Fetch die count
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530305 tmp = iterator[SPD_BYTE_6] & JEDEC_DIE_COUNT_MASK;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000306 tmp >>= JEDEC_DIE_COUNT_RIGHT_SHIFT;
307 dieCount = tmp + 1;
308 }
309
310 /* Calculate Number of ranks */
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530311 tmp = iterator[SPD_BYTE_12] & JEDEC_NUM_RANKS_MASK;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000312 tmp >>= JEDEC_RESERVED_BITS;
313
314 if (tmp > JEDEC_RESERVED_BITS)
315 {
316 cerr << "Can't calculate number of ranks. Invalid data found.\n ";
317 return dimmSize;
318 }
319 logicalRanksPerDimm = (tmp + 1) * dieCount;
320
321 dimmSize = (sdramCap / JEDEC_PRI_BUS_WIDTH_MULTIPLIER) *
322 (priBusWid / sdramWid) * logicalRanksPerDimm;
323
girik91e784d2023-05-22 02:21:16 -0500324 return constants::CONVERT_MB_TO_KB * dimmSize;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000325}
326
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530327size_t memoryVpdParser::getDDimmSize(Binary::const_iterator iterator)
328{
329 size_t dimmSize = 0;
330 if ((iterator[constants::SPD_BYTE_2] & constants::SPD_BYTE_MASK) ==
331 constants::SPD_DRAM_TYPE_DDR4)
332 {
333 dimmSize = getDdr4BasedDDimmSize(iterator);
334 }
335 else if ((iterator[constants::SPD_BYTE_2] & constants::SPD_BYTE_MASK) ==
336 constants::SPD_DRAM_TYPE_DDR5)
337 {
338 dimmSize = getDdr5BasedDDimmSize(iterator);
339 }
340 else
341 {
342 cerr << "Error: DDIMM is neither DDR4 nor DDR5. DDIMM Byte 2 value ["
343 << iterator[constants::SPD_BYTE_2] << "]";
344 }
345 return dimmSize;
346}
347
SunnySrivastava1984e12b1812020-05-26 02:23:11 -0500348kwdVpdMap memoryVpdParser::readKeywords(Binary::const_iterator iterator)
Alpana Kumaria00936f2020-04-14 07:15:46 -0500349{
350 KeywordVpdMap map{};
351
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000352 // collect Dimm size value
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530353 auto dimmSize = getDDimmSize(iterator);
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000354 if (!dimmSize)
355 {
356 cerr << "Error: Calculated dimm size is 0.";
357 }
358
359 map.emplace("MemorySizeInKB", dimmSize);
360 // point the iterator to DIMM data and skip "11S"
361 advance(iterator, MEMORY_VPD_DATA_START + 3);
Alpana Kumari80f15342020-06-09 07:41:02 -0500362 Binary partNumber(iterator, iterator + PART_NUM_LEN);
Alpana Kumaria00936f2020-04-14 07:15:46 -0500363
364 advance(iterator, PART_NUM_LEN);
Alpana Kumari80f15342020-06-09 07:41:02 -0500365 Binary serialNumber(iterator, iterator + SERIAL_NUM_LEN);
Alpana Kumaria00936f2020-04-14 07:15:46 -0500366
367 advance(iterator, SERIAL_NUM_LEN);
Alpana Kumari80f15342020-06-09 07:41:02 -0500368 Binary ccin(iterator, iterator + CCIN_LEN);
Alpana Kumaria00936f2020-04-14 07:15:46 -0500369
Sunny Srivastava172e74f2024-05-21 02:02:05 -0500370 Binary mfgId(DRAM_MANUFACTURER_ID_LENGTH);
371 std::copy_n((memVpd.cbegin() + DRAM_MANUFACTURER_ID_OFFSET),
372 DRAM_MANUFACTURER_ID_LENGTH, mfgId.begin());
373
Santosh Puranikc68bb912022-07-29 20:15:54 +0530374 map.emplace("FN", partNumber);
Alpana Kumaria00936f2020-04-14 07:15:46 -0500375 map.emplace("PN", move(partNumber));
376 map.emplace("SN", move(serialNumber));
377 map.emplace("CC", move(ccin));
Sunny Srivastava172e74f2024-05-21 02:02:05 -0500378 map.emplace("DI", move(mfgId));
Alpana Kumaria00936f2020-04-14 07:15:46 -0500379
380 return map;
381}
382
SunnySrivastava1984e12b1812020-05-26 02:23:11 -0500383variant<kwdVpdMap, Store> memoryVpdParser::parse()
Alpana Kumaria00936f2020-04-14 07:15:46 -0500384{
Alpana Kumaria00936f2020-04-14 07:15:46 -0500385 // Read the data and return the map
386 auto iterator = memVpd.cbegin();
Alpana Kumaria00936f2020-04-14 07:15:46 -0500387 auto vpdDataMap = readKeywords(iterator);
388
389 return vpdDataMap;
390}
391
SunnySrivastava1984e12b1812020-05-26 02:23:11 -0500392std::string memoryVpdParser::getInterfaceName() const
393{
394 return memVpdInf;
395}
396
Alpana Kumaria00936f2020-04-14 07:15:46 -0500397} // namespace parser
398} // namespace memory
399} // namespace vpd
Patrick Williamsc78d8872023-05-10 07:50:56 -0500400} // namespace openpower