xref: /openbmc/openpower-vpd-parser/vpd-parser/memory_vpd_parser.cpp (revision c78d887ccac761a70f2682fe3d5b948383cf56bd)
1 #include "memory_vpd_parser.hpp"
2 
3 #include <iostream>
4 #include <numeric>
5 #include <string>
6 
7 namespace openpower
8 {
9 namespace vpd
10 {
11 namespace memory
12 {
13 namespace parser
14 {
15 using namespace inventory;
16 using namespace constants;
17 using namespace std;
18 using namespace openpower::vpd::parser;
19 
20 static constexpr auto MEM_BYTE_4 = 4;
21 static constexpr auto MEM_BYTE_6 = 6;
22 static constexpr auto MEM_BYTE_12 = 12;
23 static constexpr auto MEM_BYTE_13 = 13;
24 static constexpr auto JEDEC_SDRAM_CAP_MASK = 0x0F;
25 static constexpr auto JEDEC_PRI_BUS_WIDTH_MASK = 0x07;
26 static constexpr auto JEDEC_SDRAM_WIDTH_MASK = 0x07;
27 static constexpr auto JEDEC_NUM_RANKS_MASK = 0x38;
28 static constexpr auto JEDEC_DIE_COUNT_MASK = 0x70;
29 static constexpr auto JEDEC_SINGLE_LOAD_STACK = 0x02;
30 static constexpr auto JEDEC_SIGNAL_LOADING_MASK = 0x03;
31 
32 static constexpr auto JEDEC_SDRAMCAP_MULTIPLIER = 256;
33 static constexpr auto JEDEC_PRI_BUS_WIDTH_MULTIPLIER = 8;
34 static constexpr auto JEDEC_SDRAM_WIDTH_MULTIPLIER = 4;
35 static constexpr auto JEDEC_SDRAMCAP_RESERVED = 6;
36 static constexpr auto JEDEC_RESERVED_BITS = 3;
37 static constexpr auto JEDEC_DIE_COUNT_RIGHT_SHIFT = 4;
38 
39 auto memoryVpdParser::getDimmSize(Binary::const_iterator iterator)
40 {
41     size_t tmp = 0, dimmSize = 0;
42 
43     size_t sdramCap = 1, priBusWid = 1, sdramWid = 1, logicalRanksPerDimm = 1;
44     Byte dieCount = 1;
45 
46     // NOTE: This calculation is Only for DDR4
47 
48     // Calculate SDRAM  capacity
49     tmp = iterator[MEM_BYTE_4] & JEDEC_SDRAM_CAP_MASK;
50     /* Make sure the bits are not Reserved */
51     if (tmp > JEDEC_SDRAMCAP_RESERVED)
52     {
53         cerr << "Bad data in vpd byte 4. Can't calculate SDRAM capacity and so "
54                 "dimm size.\n ";
55         return dimmSize;
56     }
57 
58     sdramCap = (sdramCap << tmp) * JEDEC_SDRAMCAP_MULTIPLIER;
59 
60     /* Calculate Primary bus width */
61     tmp = iterator[MEM_BYTE_13] & JEDEC_PRI_BUS_WIDTH_MASK;
62     if (tmp > JEDEC_RESERVED_BITS)
63     {
64         cerr << "Bad data in vpd byte 13. Can't calculate primary bus width "
65                 "and so dimm size.\n ";
66         return dimmSize;
67     }
68     priBusWid = (priBusWid << tmp) * JEDEC_PRI_BUS_WIDTH_MULTIPLIER;
69 
70     /* Calculate SDRAM width */
71     tmp = iterator[MEM_BYTE_12] & JEDEC_SDRAM_WIDTH_MASK;
72     if (tmp > JEDEC_RESERVED_BITS)
73     {
74         cerr << "Bad data in vpd byte 12. Can't calculate SDRAM width and so "
75                 "dimm size.\n ";
76         return dimmSize;
77     }
78     sdramWid = (sdramWid << tmp) * JEDEC_SDRAM_WIDTH_MULTIPLIER;
79 
80     tmp = iterator[MEM_BYTE_6] & JEDEC_SIGNAL_LOADING_MASK;
81 
82     if (tmp == JEDEC_SINGLE_LOAD_STACK)
83     {
84         // Fetch die count
85         tmp = iterator[MEM_BYTE_6] & JEDEC_DIE_COUNT_MASK;
86         tmp >>= JEDEC_DIE_COUNT_RIGHT_SHIFT;
87         dieCount = tmp + 1;
88     }
89 
90     /* Calculate Number of ranks */
91     tmp = iterator[MEM_BYTE_12] & JEDEC_NUM_RANKS_MASK;
92     tmp >>= JEDEC_RESERVED_BITS;
93 
94     if (tmp > JEDEC_RESERVED_BITS)
95     {
96         cerr << "Can't calculate number of ranks. Invalid data found.\n ";
97         return dimmSize;
98     }
99     logicalRanksPerDimm = (tmp + 1) * dieCount;
100 
101     dimmSize = (sdramCap / JEDEC_PRI_BUS_WIDTH_MULTIPLIER) *
102                (priBusWid / sdramWid) * logicalRanksPerDimm;
103 
104     return dimmSize;
105 }
106 
107 kwdVpdMap memoryVpdParser::readKeywords(Binary::const_iterator iterator)
108 {
109     KeywordVpdMap map{};
110 
111     // collect Dimm size value
112     auto dimmSize = getDimmSize(iterator);
113     if (!dimmSize)
114     {
115         cerr << "Error: Calculated dimm size is 0.";
116     }
117 
118     map.emplace("MemorySizeInKB", dimmSize);
119     // point the iterator to DIMM data and skip "11S"
120     advance(iterator, MEMORY_VPD_DATA_START + 3);
121     Binary partNumber(iterator, iterator + PART_NUM_LEN);
122 
123     advance(iterator, PART_NUM_LEN);
124     Binary serialNumber(iterator, iterator + SERIAL_NUM_LEN);
125 
126     advance(iterator, SERIAL_NUM_LEN);
127     Binary ccin(iterator, iterator + CCIN_LEN);
128 
129     map.emplace("FN", partNumber);
130     map.emplace("PN", move(partNumber));
131     map.emplace("SN", move(serialNumber));
132     map.emplace("CC", move(ccin));
133 
134     return map;
135 }
136 
137 variant<kwdVpdMap, Store> memoryVpdParser::parse()
138 {
139     // Read the data and return the map
140     auto iterator = memVpd.cbegin();
141     auto vpdDataMap = readKeywords(iterator);
142 
143     return vpdDataMap;
144 }
145 
146 std::string memoryVpdParser::getInterfaceName() const
147 {
148     return memVpdInf;
149 }
150 
151 } // namespace parser
152 } // namespace memory
153 } // namespace vpd
154 } // namespace openpower
155