blob: ea45792b03f35349c94ce626f12cf44c97243093 [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;
45
46bool memoryVpdParser::checkValidValue(uint8_t l_ByteValue, uint8_t shift,
47 uint8_t minValue, uint8_t maxValue)
48{
49 l_ByteValue = l_ByteValue >> shift;
50 if ((l_ByteValue > maxValue) || (l_ByteValue < minValue))
51 {
52 cout << "Non valid Value encountered value[" << l_ByteValue
53 << "] range [" << minValue << ".." << maxValue << "] found "
54 << " " << endl;
55 return false;
56 }
57 else
58 {
59 return true;
60 }
61}
62
63uint8_t memoryVpdParser::getDDR5DensityPerDie(uint8_t l_ByteValue)
64{
65 uint8_t l_densityPerDie = SDRAM_DENSITY_PER_DIE_UNDEFINED;
66 if (l_ByteValue < constants::VALUE_5)
67 {
68 l_densityPerDie = l_ByteValue * constants::VALUE_4;
69 }
70 else
71 {
72 switch (l_ByteValue)
73 {
74 case VALUE_5:
75 l_densityPerDie = SDRAM_DENSITY_PER_DIE_24GB;
76 break;
77
78 case VALUE_6:
79 l_densityPerDie = SDRAM_DENSITY_PER_DIE_32GB;
80 break;
81
82 case VALUE_7:
83 l_densityPerDie = SDRAM_DENSITY_PER_DIE_48GB;
84 break;
85
86 case VALUE_8:
87 l_densityPerDie = SDRAM_DENSITY_PER_DIE_64GB;
88 break;
89
90 default:
91 cout << "default value encountered for density per die" << endl;
92 l_densityPerDie = SDRAM_DENSITY_PER_DIE_UNDEFINED;
93 break;
94 }
95 }
96 return l_densityPerDie;
97}
98
99uint8_t memoryVpdParser::getDDR5DiePerPackage(uint8_t l_ByteValue)
100{
101 uint8_t l_DiePerPackage = constants::VALUE_0;
102 if (l_ByteValue < constants::VALUE_2)
103 {
104 l_DiePerPackage = l_ByteValue + constants::VALUE_1;
105 }
106 else
107 {
108 l_DiePerPackage = pow(constants::VALUE_2,
109 (l_ByteValue - constants::VALUE_1));
110 }
111 return l_DiePerPackage;
112}
113
114auto memoryVpdParser::getDdr5BasedDDimmSize(Binary::const_iterator iterator)
115{
116 size_t dimmSize = 0;
117
118 do
119 {
120 if (!checkValidValue(iterator[constants::SPD_BYTE_235] &
121 constants::MASK_BYTE_BITS_01,
122 constants::SHIFT_BITS_0, constants::VALUE_1,
123 constants::VALUE_3) ||
124 !checkValidValue(iterator[constants::SPD_BYTE_235] &
125 constants::MASK_BYTE_BITS_345,
126 constants::SHIFT_BITS_3, constants::VALUE_1,
127 constants::VALUE_3))
128 {
129 std::cerr
Jinu Joy Thomasd7a6dec2024-02-19 01:10:29 -0600130 << "Capacity calculation failed for channels per DIMM. DDIMM "
131 "Byte 235 value ["
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530132 << iterator[constants::SPD_BYTE_235] << "]";
133 break;
134 }
Jinu Joy Thomasd7a6dec2024-02-19 01:10:29 -0600135 uint8_t l_channelsPerPhy =
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530136 (((iterator[constants::SPD_BYTE_235] & constants::MASK_BYTE_BITS_01)
137 ? constants::VALUE_1
138 : constants::VALUE_0) +
139 ((iterator[constants::SPD_BYTE_235] &
140 constants::MASK_BYTE_BITS_345)
141 ? constants::VALUE_1
142 : constants::VALUE_0));
143
Jinu Joy Thomasd7a6dec2024-02-19 01:10:29 -0600144 uint8_t l_channelsPerDdimm = (((iterator[constants::SPD_BYTE_235] &
145 constants::MASK_BYTE_BITS_6) >>
146 constants::VALUE_6) +
147 ((iterator[constants::SPD_BYTE_235] &
148 constants::MASK_BYTE_BITS_7) >>
149 constants::VALUE_7)) *
150 l_channelsPerPhy;
151
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530152 if (!checkValidValue(iterator[constants::SPD_BYTE_235] &
153 constants::MASK_BYTE_BITS_012,
154 constants::SHIFT_BITS_0, constants::VALUE_1,
155 constants::VALUE_3))
156 {
157 std::cerr
Jinu Joy Thomasd7a6dec2024-02-19 01:10:29 -0600158 << "Capacity calculation failed for bus width per channel. "
159 "DDIMM Byte 235 value ["
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530160 << iterator[constants::SPD_BYTE_235] << "]";
161 break;
162 }
163 uint8_t l_busWidthPerChannel =
164 (iterator[constants::SPD_BYTE_235] & constants::MASK_BYTE_BITS_012)
165 ? PRIMARY_BUS_WIDTH_32_BITS
166 : PRIMARY_BUS_WIDTH_UNUSED;
167
168 if (!checkValidValue(iterator[constants::SPD_BYTE_4] &
169 constants::MASK_BYTE_BITS_567,
170 constants::SHIFT_BITS_5, constants::VALUE_0,
171 constants::VALUE_5))
172 {
173 std::cerr
Jinu Joy Thomasd7a6dec2024-02-19 01:10:29 -0600174 << "Capacity calculation failed for die per package. DDIMM "
175 "Byte 4 value ["
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530176 << iterator[constants::SPD_BYTE_4] << "]";
177 break;
178 }
179 uint8_t l_diePerPackage = getDDR5DiePerPackage(
180 (iterator[constants::SPD_BYTE_4] & constants::MASK_BYTE_BITS_567) >>
181 constants::VALUE_5);
182
183 if (!checkValidValue(iterator[constants::SPD_BYTE_4] &
184 constants::MASK_BYTE_BITS_01234,
185 constants::SHIFT_BITS_0, constants::VALUE_1,
186 constants::VALUE_8))
187 {
188 std::cerr
Jinu Joy Thomasd7a6dec2024-02-19 01:10:29 -0600189 << "Capacity calculation failed for SDRAM Density per Die. "
190 "DDIMM Byte 4 value ["
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530191 << iterator[constants::SPD_BYTE_4] << "]";
192 break;
193 }
194 uint8_t l_densityPerDie = getDDR5DensityPerDie(
195 iterator[constants::SPD_BYTE_4] & constants::MASK_BYTE_BITS_01234);
196
Jinu Joy Thomasd7a6dec2024-02-19 01:10:29 -0600197 uint8_t l_ranksPerChannel = 0;
198 if (((iterator[constants::SPD_BYTE_235] &
199 constants::MASK_BYTE_BITS_7) >>
200 constants::VALUE_7))
201 {
202 l_ranksPerChannel = ((iterator[constants::SPD_BYTE_234] &
203 constants::MASK_BYTE_BITS_345) >>
204 constants::VALUE_3) +
205 constants::VALUE_1;
206 }
207 else if (((iterator[constants::SPD_BYTE_235] &
208 constants::MASK_BYTE_BITS_6) >>
209 constants::VALUE_6))
210 {
211 l_ranksPerChannel = (iterator[constants::SPD_BYTE_234] &
212 constants::MASK_BYTE_BITS_012) +
213 constants::VALUE_1;
214 }
215#if 0
216 // Old Style capacity calculation kept for reference
217 // will be removed later
218 uint8_t l_ranksPerChannel =
219 (((iterator[constants::SPD_BYTE_234] &
220 constants::MASK_BYTE_BITS_345) >>
221 constants::VALUE_3) *
222 ((iterator[constants::SPD_BYTE_235] &
223 constants::MASK_BYTE_BITS_7) >>
224 constants::VALUE_7)) +
225 ((iterator[constants::SPD_BYTE_234] &
226 constants::MASK_BYTE_BITS_012) +
227 constants::VALUE_2 * ((iterator[constants::SPD_BYTE_235] &
228 constants::MASK_BYTE_BITS_6) >>
229 constants::VALUE_6));
230#endif
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530231
232 if (!checkValidValue(iterator[constants::SPD_BYTE_6] &
233 constants::MASK_BYTE_BITS_567,
234 constants::SHIFT_BITS_5, constants::VALUE_0,
235 constants::VALUE_3))
236 {
237 std::cout
238 << "Capacity calculation failed for dram width DDIMM Byte 6 value ["
239 << iterator[constants::SPD_BYTE_6] << "]";
240 break;
241 }
242 uint8_t l_dramWidth = VALUE_4 *
243 (VALUE_1 << ((iterator[constants::SPD_BYTE_6] &
244 constants::MASK_BYTE_BITS_567) >>
245 constants::VALUE_5));
246
Jinu Joy Thomasd7a6dec2024-02-19 01:10:29 -0600247 dimmSize = (l_channelsPerDdimm * l_busWidthPerChannel *
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530248 l_diePerPackage * l_densityPerDie * l_ranksPerChannel) /
249 (8 * l_dramWidth);
250
jinuthomas777f3492023-10-10 06:17:14 -0500251 } while (false);
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530252
Jinu Joy Thomas60c68e02024-02-05 22:07:32 -0600253 return constants::CONVERT_GB_TO_KB * dimmSize;
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530254}
255
256auto memoryVpdParser::getDdr4BasedDDimmSize(Binary::const_iterator iterator)
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000257{
258 size_t tmp = 0, dimmSize = 0;
259
260 size_t sdramCap = 1, priBusWid = 1, sdramWid = 1, logicalRanksPerDimm = 1;
261 Byte dieCount = 1;
262
263 // NOTE: This calculation is Only for DDR4
264
265 // Calculate SDRAM capacity
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530266 tmp = iterator[SPD_BYTE_4] & JEDEC_SDRAM_CAP_MASK;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000267 /* Make sure the bits are not Reserved */
268 if (tmp > JEDEC_SDRAMCAP_RESERVED)
269 {
270 cerr << "Bad data in vpd byte 4. Can't calculate SDRAM capacity and so "
271 "dimm size.\n ";
272 return dimmSize;
273 }
274
275 sdramCap = (sdramCap << tmp) * JEDEC_SDRAMCAP_MULTIPLIER;
276
277 /* Calculate Primary bus width */
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530278 tmp = iterator[SPD_BYTE_13] & JEDEC_PRI_BUS_WIDTH_MASK;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000279 if (tmp > JEDEC_RESERVED_BITS)
280 {
281 cerr << "Bad data in vpd byte 13. Can't calculate primary bus width "
282 "and so dimm size.\n ";
283 return dimmSize;
284 }
285 priBusWid = (priBusWid << tmp) * JEDEC_PRI_BUS_WIDTH_MULTIPLIER;
286
287 /* Calculate SDRAM width */
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530288 tmp = iterator[SPD_BYTE_12] & JEDEC_SDRAM_WIDTH_MASK;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000289 if (tmp > JEDEC_RESERVED_BITS)
290 {
291 cerr << "Bad data in vpd byte 12. Can't calculate SDRAM width and so "
292 "dimm size.\n ";
293 return dimmSize;
294 }
295 sdramWid = (sdramWid << tmp) * JEDEC_SDRAM_WIDTH_MULTIPLIER;
296
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530297 tmp = iterator[SPD_BYTE_6] & JEDEC_SIGNAL_LOADING_MASK;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000298
299 if (tmp == JEDEC_SINGLE_LOAD_STACK)
300 {
301 // Fetch die count
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530302 tmp = iterator[SPD_BYTE_6] & JEDEC_DIE_COUNT_MASK;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000303 tmp >>= JEDEC_DIE_COUNT_RIGHT_SHIFT;
304 dieCount = tmp + 1;
305 }
306
307 /* Calculate Number of ranks */
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530308 tmp = iterator[SPD_BYTE_12] & JEDEC_NUM_RANKS_MASK;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000309 tmp >>= JEDEC_RESERVED_BITS;
310
311 if (tmp > JEDEC_RESERVED_BITS)
312 {
313 cerr << "Can't calculate number of ranks. Invalid data found.\n ";
314 return dimmSize;
315 }
316 logicalRanksPerDimm = (tmp + 1) * dieCount;
317
318 dimmSize = (sdramCap / JEDEC_PRI_BUS_WIDTH_MULTIPLIER) *
319 (priBusWid / sdramWid) * logicalRanksPerDimm;
320
girik91e784d2023-05-22 02:21:16 -0500321 return constants::CONVERT_MB_TO_KB * dimmSize;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000322}
323
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530324size_t memoryVpdParser::getDDimmSize(Binary::const_iterator iterator)
325{
326 size_t dimmSize = 0;
327 if ((iterator[constants::SPD_BYTE_2] & constants::SPD_BYTE_MASK) ==
328 constants::SPD_DRAM_TYPE_DDR4)
329 {
330 dimmSize = getDdr4BasedDDimmSize(iterator);
331 }
332 else if ((iterator[constants::SPD_BYTE_2] & constants::SPD_BYTE_MASK) ==
333 constants::SPD_DRAM_TYPE_DDR5)
334 {
335 dimmSize = getDdr5BasedDDimmSize(iterator);
336 }
337 else
338 {
339 cerr << "Error: DDIMM is neither DDR4 nor DDR5. DDIMM Byte 2 value ["
340 << iterator[constants::SPD_BYTE_2] << "]";
341 }
342 return dimmSize;
343}
344
SunnySrivastava1984e12b1812020-05-26 02:23:11 -0500345kwdVpdMap memoryVpdParser::readKeywords(Binary::const_iterator iterator)
Alpana Kumaria00936f2020-04-14 07:15:46 -0500346{
347 KeywordVpdMap map{};
348
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000349 // collect Dimm size value
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530350 auto dimmSize = getDDimmSize(iterator);
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000351 if (!dimmSize)
352 {
353 cerr << "Error: Calculated dimm size is 0.";
354 }
355
356 map.emplace("MemorySizeInKB", dimmSize);
357 // point the iterator to DIMM data and skip "11S"
358 advance(iterator, MEMORY_VPD_DATA_START + 3);
Alpana Kumari80f15342020-06-09 07:41:02 -0500359 Binary partNumber(iterator, iterator + PART_NUM_LEN);
Alpana Kumaria00936f2020-04-14 07:15:46 -0500360
361 advance(iterator, PART_NUM_LEN);
Alpana Kumari80f15342020-06-09 07:41:02 -0500362 Binary serialNumber(iterator, iterator + SERIAL_NUM_LEN);
Alpana Kumaria00936f2020-04-14 07:15:46 -0500363
364 advance(iterator, SERIAL_NUM_LEN);
Alpana Kumari80f15342020-06-09 07:41:02 -0500365 Binary ccin(iterator, iterator + CCIN_LEN);
Alpana Kumaria00936f2020-04-14 07:15:46 -0500366
Santosh Puranikc68bb912022-07-29 20:15:54 +0530367 map.emplace("FN", partNumber);
Alpana Kumaria00936f2020-04-14 07:15:46 -0500368 map.emplace("PN", move(partNumber));
369 map.emplace("SN", move(serialNumber));
370 map.emplace("CC", move(ccin));
371
372 return map;
373}
374
SunnySrivastava1984e12b1812020-05-26 02:23:11 -0500375variant<kwdVpdMap, Store> memoryVpdParser::parse()
Alpana Kumaria00936f2020-04-14 07:15:46 -0500376{
Alpana Kumaria00936f2020-04-14 07:15:46 -0500377 // Read the data and return the map
378 auto iterator = memVpd.cbegin();
Alpana Kumaria00936f2020-04-14 07:15:46 -0500379 auto vpdDataMap = readKeywords(iterator);
380
381 return vpdDataMap;
382}
383
SunnySrivastava1984e12b1812020-05-26 02:23:11 -0500384std::string memoryVpdParser::getInterfaceName() const
385{
386 return memVpdInf;
387}
388
Alpana Kumaria00936f2020-04-14 07:15:46 -0500389} // namespace parser
390} // namespace memory
391} // namespace vpd
Patrick Williamsc78d8872023-05-10 07:50:56 -0500392} // namespace openpower