xref: /openbmc/smbios-mdr/src/dimm.cpp (revision 1cf66fee)
1 /*
2 // Copyright (c) 2018 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 
17 #include "dimm.hpp"
18 
19 #include "mdrv2.hpp"
20 
21 #include <boost/algorithm/string.hpp>
22 #include <phosphor-logging/elog-errors.hpp>
23 
24 namespace phosphor
25 {
26 namespace smbios
27 {
28 
29 #ifdef DIMM_ONLY_LOCATOR
30 bool onlyDimmLocationCode = true;
31 #else
32 bool onlyDimmLocationCode = false;
33 #endif
34 
35 using DeviceType =
36     sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::DeviceType;
37 
38 using EccType =
39     sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::Ecc;
40 
41 static constexpr uint16_t maxOldDimmSize = 0x7fff;
42 void Dimm::memoryInfoUpdate(void)
43 {
44     uint8_t* dataIn = storage;
45 
46     dataIn = getSMBIOSTypePtr(dataIn, memoryDeviceType);
47 
48     if (dataIn == nullptr)
49     {
50         return;
51     }
52     for (uint8_t index = 0; index < dimmNum; index++)
53     {
54         dataIn = smbiosNextPtr(dataIn);
55         if (dataIn == nullptr)
56         {
57             return;
58         }
59         dataIn = getSMBIOSTypePtr(dataIn, memoryDeviceType);
60         if (dataIn == nullptr)
61         {
62             return;
63         }
64     }
65 
66     auto memoryInfo = reinterpret_cast<struct MemoryInfo*>(dataIn);
67 
68     memoryDataWidth(memoryInfo->dataWidth);
69 
70     if (memoryInfo->size == maxOldDimmSize)
71     {
72         dimmSizeExt(memoryInfo->extendedSize);
73     }
74     else
75     {
76         dimmSize(memoryInfo->size);
77     }
78     // If the size is 0, no memory device is installed in the socket.
79     const auto isDimmPresent = memoryInfo->size > 0;
80     present(isDimmPresent);
81     functional(isDimmPresent);
82 
83     dimmDeviceLocator(memoryInfo->bankLocator, memoryInfo->deviceLocator,
84                       memoryInfo->length, dataIn);
85     dimmType(memoryInfo->memoryType);
86     dimmTypeDetail(memoryInfo->typeDetail);
87     maxMemorySpeedInMhz(memoryInfo->speed);
88     dimmManufacturer(memoryInfo->manufacturer, memoryInfo->length, dataIn);
89     dimmSerialNum(memoryInfo->serialNum, memoryInfo->length, dataIn);
90     dimmPartNum(memoryInfo->partNum, memoryInfo->length, dataIn);
91     memoryAttributes(memoryInfo->attributes);
92     memoryConfiguredSpeedInMhz(memoryInfo->confClockSpeed);
93 
94     updateEccType(memoryInfo->phyArrayHandle);
95 
96     if (!motherboardPath.empty())
97     {
98         std::vector<std::tuple<std::string, std::string, std::string>> assocs;
99         assocs.emplace_back("chassis", "memories", motherboardPath);
100         association::associations(assocs);
101     }
102 
103     return;
104 }
105 
106 void Dimm::updateEccType(uint16_t exPhyArrayHandle)
107 {
108     uint8_t* dataIn = storage;
109 
110     while (dataIn != nullptr)
111     {
112         dataIn = getSMBIOSTypePtr(dataIn, physicalMemoryArrayType);
113         if (dataIn == nullptr)
114         {
115             phosphor::logging::log<phosphor::logging::level::ERR>(
116                 "Failed to get SMBIOS table type-16 data.");
117             return;
118         }
119 
120         auto info = reinterpret_cast<struct PhysicalMemoryArrayInfo*>(dataIn);
121         if (info->handle == exPhyArrayHandle)
122         {
123             std::map<uint8_t, EccType>::const_iterator it =
124                 dimmEccTypeMap.find(info->memoryErrorCorrection);
125             if (it == dimmEccTypeMap.end())
126             {
127                 ecc(EccType::NoECC);
128             }
129             else
130             {
131                 ecc(it->second);
132             }
133             return;
134         }
135 
136         dataIn = smbiosNextPtr(dataIn);
137     }
138     phosphor::logging::log<phosphor::logging::level::ERR>(
139         "Failed find the corresponding SMBIOS table type-16 data for dimm:",
140         phosphor::logging::entry("DIMM:%d", dimmNum));
141 }
142 
143 EccType Dimm::ecc(EccType value)
144 {
145     return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::ecc(
146         value);
147 }
148 
149 uint16_t Dimm::memoryDataWidth(uint16_t value)
150 {
151     return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::
152         memoryDataWidth(value);
153 }
154 
155 static constexpr uint16_t baseNewVersionDimmSize = 0x8000;
156 static constexpr uint16_t dimmSizeUnit = 1024;
157 void Dimm::dimmSize(const uint16_t size)
158 {
159     size_t result = size & maxOldDimmSize;
160     if (0 == (size & baseNewVersionDimmSize))
161     {
162         result = result * dimmSizeUnit;
163     }
164     memorySizeInKB(result);
165 }
166 
167 void Dimm::dimmSizeExt(size_t size)
168 {
169     size = size * dimmSizeUnit;
170     memorySizeInKB(size);
171 }
172 
173 size_t Dimm::memorySizeInKB(size_t value)
174 {
175     return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::
176         memorySizeInKB(value);
177 }
178 
179 void Dimm::dimmDeviceLocator(const uint8_t bankLocatorPositionNum,
180                              const uint8_t deviceLocatorPositionNum,
181                              const uint8_t structLen, uint8_t* dataIn)
182 {
183     std::string deviceLocator =
184         positionToString(deviceLocatorPositionNum, structLen, dataIn);
185     std::string bankLocator =
186         positionToString(bankLocatorPositionNum, structLen, dataIn);
187 
188     std::string result;
189     if (bankLocator.empty() || onlyDimmLocationCode)
190     {
191         result = deviceLocator;
192     }
193     else
194     {
195         result = bankLocator + " " + deviceLocator;
196     }
197 
198     memoryDeviceLocator(result);
199 
200     locationCode(result);
201 }
202 
203 std::string Dimm::memoryDeviceLocator(std::string value)
204 {
205     return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::
206         memoryDeviceLocator(value);
207 }
208 
209 void Dimm::dimmType(const uint8_t type)
210 {
211     std::map<uint8_t, DeviceType>::const_iterator it = dimmTypeTable.find(type);
212     if (it == dimmTypeTable.end())
213     {
214         memoryType(DeviceType::Unknown);
215     }
216     else
217     {
218         memoryType(it->second);
219     }
220 }
221 
222 DeviceType Dimm::memoryType(DeviceType value)
223 {
224     return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::
225         memoryType(value);
226 }
227 
228 void Dimm::dimmTypeDetail(uint16_t detail)
229 {
230     std::string result;
231     for (uint8_t index = 0; index < (8 * sizeof(detail)); index++)
232     {
233         if (detail & 0x01)
234         {
235             result += detailTable[index];
236         }
237         detail >>= 1;
238     }
239     memoryTypeDetail(result);
240 }
241 
242 std::string Dimm::memoryTypeDetail(std::string value)
243 {
244     return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::
245         memoryTypeDetail(value);
246 }
247 
248 uint16_t Dimm::maxMemorySpeedInMhz(uint16_t value)
249 {
250     return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::
251         maxMemorySpeedInMhz(value);
252 }
253 
254 void Dimm::dimmManufacturer(const uint8_t positionNum, const uint8_t structLen,
255                             uint8_t* dataIn)
256 {
257     std::string result = positionToString(positionNum, structLen, dataIn);
258 
259     if (result == "NO DIMM")
260     {
261         // No dimm presence so making manufacturer value as "" (instead of
262         // NO DIMM - as there won't be any manufacturer for DIMM which is not
263         // present).
264         result = "";
265     }
266     manufacturer(result);
267 }
268 
269 std::string Dimm::manufacturer(std::string value)
270 {
271     return sdbusplus::xyz::openbmc_project::Inventory::Decorator::server::
272         Asset::manufacturer(value);
273 }
274 
275 bool Dimm::present(bool value)
276 {
277     return sdbusplus::xyz::openbmc_project::Inventory::server::Item::present(
278         value);
279 }
280 
281 void Dimm::dimmSerialNum(const uint8_t positionNum, const uint8_t structLen,
282                          uint8_t* dataIn)
283 {
284     std::string result = positionToString(positionNum, structLen, dataIn);
285 
286     serialNumber(result);
287 }
288 
289 std::string Dimm::serialNumber(std::string value)
290 {
291     return sdbusplus::xyz::openbmc_project::Inventory::Decorator::server::
292         Asset::serialNumber(value);
293 }
294 
295 void Dimm::dimmPartNum(const uint8_t positionNum, const uint8_t structLen,
296                        uint8_t* dataIn)
297 {
298     std::string result = positionToString(positionNum, structLen, dataIn);
299 
300     // Part number could contain spaces at the end. Eg: "abcd123  ". Since its
301     // unnecessary, we should remove them.
302     boost::algorithm::trim_right(result);
303     partNumber(result);
304 }
305 
306 std::string Dimm::partNumber(std::string value)
307 {
308     return sdbusplus::xyz::openbmc_project::Inventory::Decorator::server::
309         Asset::partNumber(value);
310 }
311 
312 std::string Dimm::locationCode(std::string value)
313 {
314     return sdbusplus::xyz::openbmc_project::Inventory::Decorator::server::
315         LocationCode::locationCode(value);
316 }
317 
318 uint8_t Dimm::memoryAttributes(uint8_t value)
319 {
320     return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::
321         memoryAttributes(value);
322 }
323 
324 uint16_t Dimm::memoryConfiguredSpeedInMhz(uint16_t value)
325 {
326     return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::
327         memoryConfiguredSpeedInMhz(value);
328 }
329 
330 bool Dimm::functional(bool value)
331 {
332     return sdbusplus::xyz::openbmc_project::State::Decorator::server::
333         OperationalStatus::functional(value);
334 }
335 
336 } // namespace smbios
337 } // namespace phosphor
338