blob: 30e44aaf81574de5ab660c61d646c5e609351050 [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
130 << "Capacity calculation failed for channels per DIMM. DDIMM Byte 235 value ["
131 << iterator[constants::SPD_BYTE_235] << "]";
132 break;
133 }
134 uint8_t l_channelsPerDDimm =
135 (((iterator[constants::SPD_BYTE_235] & constants::MASK_BYTE_BITS_01)
136 ? constants::VALUE_1
137 : constants::VALUE_0) +
138 ((iterator[constants::SPD_BYTE_235] &
139 constants::MASK_BYTE_BITS_345)
140 ? constants::VALUE_1
141 : constants::VALUE_0));
142
143 if (!checkValidValue(iterator[constants::SPD_BYTE_235] &
144 constants::MASK_BYTE_BITS_012,
145 constants::SHIFT_BITS_0, constants::VALUE_1,
146 constants::VALUE_3))
147 {
148 std::cerr
149 << "Capacity calculation failed for bus width per channel. DDIMM Byte 235 value ["
150 << iterator[constants::SPD_BYTE_235] << "]";
151 break;
152 }
153 uint8_t l_busWidthPerChannel =
154 (iterator[constants::SPD_BYTE_235] & constants::MASK_BYTE_BITS_012)
155 ? PRIMARY_BUS_WIDTH_32_BITS
156 : PRIMARY_BUS_WIDTH_UNUSED;
157
158 if (!checkValidValue(iterator[constants::SPD_BYTE_4] &
159 constants::MASK_BYTE_BITS_567,
160 constants::SHIFT_BITS_5, constants::VALUE_0,
161 constants::VALUE_5))
162 {
163 std::cerr
164 << "Capacity calculation failed for die per package. DDIMM Byte 4 value ["
165 << iterator[constants::SPD_BYTE_4] << "]";
166 break;
167 }
168 uint8_t l_diePerPackage = getDDR5DiePerPackage(
169 (iterator[constants::SPD_BYTE_4] & constants::MASK_BYTE_BITS_567) >>
170 constants::VALUE_5);
171
172 if (!checkValidValue(iterator[constants::SPD_BYTE_4] &
173 constants::MASK_BYTE_BITS_01234,
174 constants::SHIFT_BITS_0, constants::VALUE_1,
175 constants::VALUE_8))
176 {
177 std::cerr
178 << "Capacity calculation failed for SDRAM Density per Die. DDIMM Byte 4 value ["
179 << iterator[constants::SPD_BYTE_4] << "]";
180 break;
181 }
182 uint8_t l_densityPerDie = getDDR5DensityPerDie(
183 iterator[constants::SPD_BYTE_4] & constants::MASK_BYTE_BITS_01234);
184
185 uint8_t l_ranksPerChannel = ((iterator[constants::SPD_BYTE_234] &
186 constants::MASK_BYTE_BITS_345) >>
187 constants::VALUE_3) +
188 (iterator[constants::SPD_BYTE_234] &
189 constants::MASK_BYTE_BITS_012) +
190 constants::VALUE_2;
191
192 if (!checkValidValue(iterator[constants::SPD_BYTE_6] &
193 constants::MASK_BYTE_BITS_567,
194 constants::SHIFT_BITS_5, constants::VALUE_0,
195 constants::VALUE_3))
196 {
197 std::cout
198 << "Capacity calculation failed for dram width DDIMM Byte 6 value ["
199 << iterator[constants::SPD_BYTE_6] << "]";
200 break;
201 }
202 uint8_t l_dramWidth = VALUE_4 *
203 (VALUE_1 << ((iterator[constants::SPD_BYTE_6] &
204 constants::MASK_BYTE_BITS_567) >>
205 constants::VALUE_5));
206
207 dimmSize = (l_channelsPerDDimm * l_busWidthPerChannel *
208 l_diePerPackage * l_densityPerDie * l_ranksPerChannel) /
209 (8 * l_dramWidth);
210
jinuthomas777f3492023-10-10 06:17:14 -0500211 } while (false);
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530212
Jinu Joy Thomas60c68e02024-02-05 22:07:32 -0600213 return constants::CONVERT_GB_TO_KB * dimmSize;
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530214}
215
216auto memoryVpdParser::getDdr4BasedDDimmSize(Binary::const_iterator iterator)
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000217{
218 size_t tmp = 0, dimmSize = 0;
219
220 size_t sdramCap = 1, priBusWid = 1, sdramWid = 1, logicalRanksPerDimm = 1;
221 Byte dieCount = 1;
222
223 // NOTE: This calculation is Only for DDR4
224
225 // Calculate SDRAM capacity
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530226 tmp = iterator[SPD_BYTE_4] & JEDEC_SDRAM_CAP_MASK;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000227 /* Make sure the bits are not Reserved */
228 if (tmp > JEDEC_SDRAMCAP_RESERVED)
229 {
230 cerr << "Bad data in vpd byte 4. Can't calculate SDRAM capacity and so "
231 "dimm size.\n ";
232 return dimmSize;
233 }
234
235 sdramCap = (sdramCap << tmp) * JEDEC_SDRAMCAP_MULTIPLIER;
236
237 /* Calculate Primary bus width */
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530238 tmp = iterator[SPD_BYTE_13] & JEDEC_PRI_BUS_WIDTH_MASK;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000239 if (tmp > JEDEC_RESERVED_BITS)
240 {
241 cerr << "Bad data in vpd byte 13. Can't calculate primary bus width "
242 "and so dimm size.\n ";
243 return dimmSize;
244 }
245 priBusWid = (priBusWid << tmp) * JEDEC_PRI_BUS_WIDTH_MULTIPLIER;
246
247 /* Calculate SDRAM width */
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530248 tmp = iterator[SPD_BYTE_12] & JEDEC_SDRAM_WIDTH_MASK;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000249 if (tmp > JEDEC_RESERVED_BITS)
250 {
251 cerr << "Bad data in vpd byte 12. Can't calculate SDRAM width and so "
252 "dimm size.\n ";
253 return dimmSize;
254 }
255 sdramWid = (sdramWid << tmp) * JEDEC_SDRAM_WIDTH_MULTIPLIER;
256
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530257 tmp = iterator[SPD_BYTE_6] & JEDEC_SIGNAL_LOADING_MASK;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000258
259 if (tmp == JEDEC_SINGLE_LOAD_STACK)
260 {
261 // Fetch die count
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530262 tmp = iterator[SPD_BYTE_6] & JEDEC_DIE_COUNT_MASK;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000263 tmp >>= JEDEC_DIE_COUNT_RIGHT_SHIFT;
264 dieCount = tmp + 1;
265 }
266
267 /* Calculate Number of ranks */
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530268 tmp = iterator[SPD_BYTE_12] & JEDEC_NUM_RANKS_MASK;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000269 tmp >>= JEDEC_RESERVED_BITS;
270
271 if (tmp > JEDEC_RESERVED_BITS)
272 {
273 cerr << "Can't calculate number of ranks. Invalid data found.\n ";
274 return dimmSize;
275 }
276 logicalRanksPerDimm = (tmp + 1) * dieCount;
277
278 dimmSize = (sdramCap / JEDEC_PRI_BUS_WIDTH_MULTIPLIER) *
279 (priBusWid / sdramWid) * logicalRanksPerDimm;
280
girik91e784d2023-05-22 02:21:16 -0500281 return constants::CONVERT_MB_TO_KB * dimmSize;
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000282}
283
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530284size_t memoryVpdParser::getDDimmSize(Binary::const_iterator iterator)
285{
286 size_t dimmSize = 0;
287 if ((iterator[constants::SPD_BYTE_2] & constants::SPD_BYTE_MASK) ==
288 constants::SPD_DRAM_TYPE_DDR4)
289 {
290 dimmSize = getDdr4BasedDDimmSize(iterator);
291 }
292 else if ((iterator[constants::SPD_BYTE_2] & constants::SPD_BYTE_MASK) ==
293 constants::SPD_DRAM_TYPE_DDR5)
294 {
295 dimmSize = getDdr5BasedDDimmSize(iterator);
296 }
297 else
298 {
299 cerr << "Error: DDIMM is neither DDR4 nor DDR5. DDIMM Byte 2 value ["
300 << iterator[constants::SPD_BYTE_2] << "]";
301 }
302 return dimmSize;
303}
304
SunnySrivastava1984e12b1812020-05-26 02:23:11 -0500305kwdVpdMap memoryVpdParser::readKeywords(Binary::const_iterator iterator)
Alpana Kumaria00936f2020-04-14 07:15:46 -0500306{
307 KeywordVpdMap map{};
308
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000309 // collect Dimm size value
Jinu Joy Thomasdb43bcd2023-08-17 09:40:16 +0530310 auto dimmSize = getDDimmSize(iterator);
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000311 if (!dimmSize)
312 {
313 cerr << "Error: Calculated dimm size is 0.";
314 }
315
316 map.emplace("MemorySizeInKB", dimmSize);
317 // point the iterator to DIMM data and skip "11S"
318 advance(iterator, MEMORY_VPD_DATA_START + 3);
Alpana Kumari80f15342020-06-09 07:41:02 -0500319 Binary partNumber(iterator, iterator + PART_NUM_LEN);
Alpana Kumaria00936f2020-04-14 07:15:46 -0500320
321 advance(iterator, PART_NUM_LEN);
Alpana Kumari80f15342020-06-09 07:41:02 -0500322 Binary serialNumber(iterator, iterator + SERIAL_NUM_LEN);
Alpana Kumaria00936f2020-04-14 07:15:46 -0500323
324 advance(iterator, SERIAL_NUM_LEN);
Alpana Kumari80f15342020-06-09 07:41:02 -0500325 Binary ccin(iterator, iterator + CCIN_LEN);
Alpana Kumaria00936f2020-04-14 07:15:46 -0500326
Santosh Puranikc68bb912022-07-29 20:15:54 +0530327 map.emplace("FN", partNumber);
Alpana Kumaria00936f2020-04-14 07:15:46 -0500328 map.emplace("PN", move(partNumber));
329 map.emplace("SN", move(serialNumber));
330 map.emplace("CC", move(ccin));
331
332 return map;
333}
334
SunnySrivastava1984e12b1812020-05-26 02:23:11 -0500335variant<kwdVpdMap, Store> memoryVpdParser::parse()
Alpana Kumaria00936f2020-04-14 07:15:46 -0500336{
Alpana Kumaria00936f2020-04-14 07:15:46 -0500337 // Read the data and return the map
338 auto iterator = memVpd.cbegin();
Alpana Kumaria00936f2020-04-14 07:15:46 -0500339 auto vpdDataMap = readKeywords(iterator);
340
341 return vpdDataMap;
342}
343
SunnySrivastava1984e12b1812020-05-26 02:23:11 -0500344std::string memoryVpdParser::getInterfaceName() const
345{
346 return memVpdInf;
347}
348
Alpana Kumaria00936f2020-04-14 07:15:46 -0500349} // namespace parser
350} // namespace memory
351} // namespace vpd
Patrick Williamsc78d8872023-05-10 07:50:56 -0500352} // namespace openpower