xref: /openbmc/smbios-mdr/src/dimm.cpp (revision 410bbc27)
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 #include <regex>
25 
26 namespace phosphor
27 {
28 namespace smbios
29 {
30 
31 #ifdef DIMM_ONLY_LOCATOR
32 bool onlyDimmLocationCode = true;
33 #else
34 bool onlyDimmLocationCode = false;
35 #endif
36 
37 using DeviceType =
38     sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::DeviceType;
39 
40 using EccType =
41     sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::Ecc;
42 
43 static constexpr uint16_t maxOldDimmSize = 0x7fff;
memoryInfoUpdate(uint8_t * smbiosTableStorage,const std::string & motherboard)44 void Dimm::memoryInfoUpdate(uint8_t* smbiosTableStorage,
45                             const std::string& motherboard)
46 {
47     storage = smbiosTableStorage;
48     motherboardPath = motherboard;
49 
50     uint8_t* dataIn = storage;
51 
52     dataIn = getSMBIOSTypePtr(dataIn, memoryDeviceType);
53 
54     if (dataIn == nullptr)
55     {
56         return;
57     }
58     for (uint8_t index = 0; index < dimmNum; index++)
59     {
60         dataIn = smbiosNextPtr(dataIn);
61         if (dataIn == nullptr)
62         {
63             return;
64         }
65         dataIn = getSMBIOSTypePtr(dataIn, memoryDeviceType);
66         if (dataIn == nullptr)
67         {
68             return;
69         }
70     }
71 
72     auto memoryInfo = reinterpret_cast<struct MemoryInfo*>(dataIn);
73 
74     memoryDataWidth(memoryInfo->dataWidth);
75     memoryTotalWidth(memoryInfo->totalWidth);
76 
77     if (memoryInfo->size == maxOldDimmSize)
78     {
79         dimmSizeExt(memoryInfo->extendedSize);
80     }
81     else
82     {
83         dimmSize(memoryInfo->size);
84     }
85     // If the size is 0, no memory device is installed in the socket.
86     const auto isDimmPresent = memoryInfo->size > 0;
87     present(isDimmPresent);
88     functional(isDimmPresent);
89 
90     dimmDeviceLocator(memoryInfo->bankLocator, memoryInfo->deviceLocator,
91                       memoryInfo->length, dataIn);
92     dimmType(memoryInfo->memoryType);
93     dimmTypeDetail(memoryInfo->typeDetail);
94     maxMemorySpeedInMhz(memoryInfo->speed);
95     dimmManufacturer(memoryInfo->manufacturer, memoryInfo->length, dataIn);
96     dimmSerialNum(memoryInfo->serialNum, memoryInfo->length, dataIn);
97     dimmPartNum(memoryInfo->partNum, memoryInfo->length, dataIn);
98     memoryAttributes(memoryInfo->attributes);
99     dimmMedia(memoryInfo->memoryTechnology);
100     memoryConfiguredSpeedInMhz(memoryInfo->confClockSpeed);
101 
102     updateEccType(memoryInfo->phyArrayHandle);
103 
104     if (!motherboardPath.empty())
105     {
106         std::vector<std::tuple<std::string, std::string, std::string>> assocs;
107         assocs.emplace_back("chassis", "memories", motherboardPath);
108         association::associations(assocs);
109     }
110 
111     return;
112 }
113 
updateEccType(uint16_t exPhyArrayHandle)114 void Dimm::updateEccType(uint16_t exPhyArrayHandle)
115 {
116     uint8_t* dataIn = storage;
117 
118     while (dataIn != nullptr)
119     {
120         dataIn = getSMBIOSTypePtr(dataIn, physicalMemoryArrayType);
121         if (dataIn == nullptr)
122         {
123             phosphor::logging::log<phosphor::logging::level::ERR>(
124                 "Failed to get SMBIOS table type-16 data.");
125             return;
126         }
127 
128         auto info = reinterpret_cast<struct PhysicalMemoryArrayInfo*>(dataIn);
129         if (info->handle == exPhyArrayHandle)
130         {
131             std::map<uint8_t, EccType>::const_iterator it =
132                 dimmEccTypeMap.find(info->memoryErrorCorrection);
133             if (it == dimmEccTypeMap.end())
134             {
135                 ecc(EccType::NoECC);
136             }
137             else
138             {
139                 ecc(it->second);
140             }
141             return;
142         }
143 
144         dataIn = smbiosNextPtr(dataIn);
145     }
146     phosphor::logging::log<phosphor::logging::level::ERR>(
147         "Failed find the corresponding SMBIOS table type-16 data for dimm:",
148         phosphor::logging::entry("DIMM:%d", dimmNum));
149 }
150 
ecc(EccType value)151 EccType Dimm::ecc(EccType value)
152 {
153     return sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::ecc(
154         value);
155 }
156 
memoryDataWidth(uint16_t value)157 uint16_t Dimm::memoryDataWidth(uint16_t value)
158 {
159     return sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::
160         memoryDataWidth(value);
161 }
162 
memoryTotalWidth(uint16_t value)163 uint16_t Dimm::memoryTotalWidth(uint16_t value)
164 {
165     return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::
166         memoryTotalWidth(value);
167 }
168 
169 static constexpr uint16_t baseNewVersionDimmSize = 0x8000;
170 static constexpr uint16_t dimmSizeUnit = 1024;
dimmSize(const uint16_t size)171 void Dimm::dimmSize(const uint16_t size)
172 {
173     uint32_t result = size & maxOldDimmSize;
174     if (0 == (size & baseNewVersionDimmSize))
175     {
176         result = result * dimmSizeUnit;
177     }
178     memorySizeInKB(result);
179 }
180 
dimmSizeExt(uint32_t size)181 void Dimm::dimmSizeExt(uint32_t size)
182 {
183     size = size * dimmSizeUnit;
184     memorySizeInKB(size);
185 }
186 
memorySizeInKB(size_t value)187 size_t Dimm::memorySizeInKB(size_t value)
188 {
189     return sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::
190         memorySizeInKB(value);
191 }
192 
dimmDeviceLocator(const uint8_t bankLocatorPositionNum,const uint8_t deviceLocatorPositionNum,const uint8_t structLen,uint8_t * dataIn)193 void Dimm::dimmDeviceLocator(const uint8_t bankLocatorPositionNum,
194                              const uint8_t deviceLocatorPositionNum,
195                              const uint8_t structLen, uint8_t* dataIn)
196 {
197     std::string deviceLocator = positionToString(deviceLocatorPositionNum,
198                                                  structLen, dataIn);
199     std::string bankLocator = positionToString(bankLocatorPositionNum,
200                                                structLen, dataIn);
201 
202     std::string result;
203     if (bankLocator.empty() || onlyDimmLocationCode)
204     {
205         result = deviceLocator;
206     }
207     else
208     {
209         result = bankLocator + " " + deviceLocator;
210     }
211 
212     memoryDeviceLocator(result);
213 
214     locationCode(result);
215     const std::string substrCpu = "CPU";
216     auto cpuPos = deviceLocator.find(substrCpu);
217 
218     if (cpuPos != std::string::npos)
219     {
220         std::string socketString =
221             deviceLocator.substr(cpuPos + substrCpu.length(), 1);
222         try
223         {
224             uint8_t socketNum =
225                 static_cast<uint8_t>(std::stoi(socketString) + 1);
226             socket(socketNum);
227         }
228         catch (const sdbusplus::exception_t& ex)
229         {
230             phosphor::logging::log<phosphor::logging::level::ERR>(
231                 "std::stoi operation failed ",
232                 phosphor::logging::entry("ERROR=%s", ex.what()));
233         }
234     }
235 
236     const std::string substrDimm = "DIMM";
237     auto dimmPos = deviceLocator.find(substrDimm);
238 
239     if (dimmPos != std::string::npos)
240     {
241         std::string slotString =
242             deviceLocator.substr(dimmPos + substrDimm.length() + 1);
243         /* slotString is extracted from substrDimm (DIMM_A) if slotString is
244          * single alphabet like A, B , C.. then assign ASCII value of slotString
245          * to slot */
246         if ((std::regex_match(slotString, std::regex("^[A-Za-z]+$"))) &&
247             (slotString.length() == 1))
248         {
249             slot(static_cast<uint8_t>(toupper(slotString[0])));
250         }
251     }
252 }
253 
memoryDeviceLocator(std::string value)254 std::string Dimm::memoryDeviceLocator(std::string value)
255 {
256     return sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::
257         memoryDeviceLocator(value);
258 }
259 
dimmType(const uint8_t type)260 void Dimm::dimmType(const uint8_t type)
261 {
262     std::map<uint8_t, DeviceType>::const_iterator it = dimmTypeTable.find(type);
263     if (it == dimmTypeTable.end())
264     {
265         memoryType(DeviceType::Unknown);
266     }
267     else
268     {
269         memoryType(it->second);
270     }
271 }
272 
memoryType(DeviceType value)273 DeviceType Dimm::memoryType(DeviceType value)
274 {
275     return sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::
276         memoryType(value);
277 }
278 
dimmMedia(const uint8_t type)279 void Dimm::dimmMedia(const uint8_t type)
280 {
281     std::map<uint8_t, MemoryTechType>::const_iterator it =
282         dimmMemoryTechTypeMap.find(type);
283     if (it == dimmMemoryTechTypeMap.end())
284     {
285         memoryMedia(MemoryTechType::Unknown);
286     }
287     else
288     {
289         memoryMedia(it->second);
290     }
291 }
292 
memoryMedia(MemoryTechType value)293 MemoryTechType Dimm::memoryMedia(MemoryTechType value)
294 {
295     return sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::
296         memoryMedia(value);
297 }
298 
dimmTypeDetail(uint16_t detail)299 void Dimm::dimmTypeDetail(uint16_t detail)
300 {
301     std::string result;
302     for (uint8_t index = 0; index < (8 * sizeof(detail)); index++)
303     {
304         if (detail & 0x01)
305         {
306             result += detailTable[index];
307         }
308         detail >>= 1;
309     }
310     memoryTypeDetail(result);
311 }
312 
memoryTypeDetail(std::string value)313 std::string Dimm::memoryTypeDetail(std::string value)
314 {
315     return sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::
316         memoryTypeDetail(value);
317 }
318 
maxMemorySpeedInMhz(uint16_t value)319 uint16_t Dimm::maxMemorySpeedInMhz(uint16_t value)
320 {
321     return sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::
322         maxMemorySpeedInMhz(value);
323 }
324 
dimmManufacturer(const uint8_t positionNum,const uint8_t structLen,uint8_t * dataIn)325 void Dimm::dimmManufacturer(const uint8_t positionNum, const uint8_t structLen,
326                             uint8_t* dataIn)
327 {
328     std::string result = positionToString(positionNum, structLen, dataIn);
329 
330     if (result == "NO DIMM")
331     {
332         // No dimm presence so making manufacturer value as "" (instead of
333         // NO DIMM - as there won't be any manufacturer for DIMM which is not
334         // present).
335         result = "";
336     }
337     manufacturer(result);
338 }
339 
manufacturer(std::string value)340 std::string Dimm::manufacturer(std::string value)
341 {
342     return sdbusplus::server::xyz::openbmc_project::inventory::decorator::
343         Asset::manufacturer(value);
344 }
345 
present(bool value)346 bool Dimm::present(bool value)
347 {
348     return sdbusplus::server::xyz::openbmc_project::inventory::Item::present(
349         value);
350 }
351 
dimmSerialNum(const uint8_t positionNum,const uint8_t structLen,uint8_t * dataIn)352 void Dimm::dimmSerialNum(const uint8_t positionNum, const uint8_t structLen,
353                          uint8_t* dataIn)
354 {
355     std::string result = positionToString(positionNum, structLen, dataIn);
356 
357     serialNumber(result);
358 }
359 
serialNumber(std::string value)360 std::string Dimm::serialNumber(std::string value)
361 {
362     return sdbusplus::server::xyz::openbmc_project::inventory::decorator::
363         Asset::serialNumber(value);
364 }
365 
dimmPartNum(const uint8_t positionNum,const uint8_t structLen,uint8_t * dataIn)366 void Dimm::dimmPartNum(const uint8_t positionNum, const uint8_t structLen,
367                        uint8_t* dataIn)
368 {
369     std::string result = positionToString(positionNum, structLen, dataIn);
370 
371     // Part number could contain spaces at the end. Eg: "abcd123  ". Since its
372     // unnecessary, we should remove them.
373     boost::algorithm::trim_right(result);
374     partNumber(result);
375 }
376 
partNumber(std::string value)377 std::string Dimm::partNumber(std::string value)
378 {
379     return sdbusplus::server::xyz::openbmc_project::inventory::decorator::
380         Asset::partNumber(value);
381 }
382 
locationCode(std::string value)383 std::string Dimm::locationCode(std::string value)
384 {
385     return sdbusplus::server::xyz::openbmc_project::inventory::decorator::
386         LocationCode::locationCode(value);
387 }
388 
memoryAttributes(size_t value)389 size_t Dimm::memoryAttributes(size_t value)
390 {
391     return sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::
392         memoryAttributes(value);
393 }
394 
slot(uint8_t value)395 uint8_t Dimm::slot(uint8_t value)
396 {
397     return sdbusplus::server::xyz::openbmc_project::inventory::item::dimm::
398         MemoryLocation::slot(value);
399 }
400 
socket(uint8_t value)401 uint8_t Dimm::socket(uint8_t value)
402 {
403     return sdbusplus::server::xyz::openbmc_project::inventory::item::dimm::
404         MemoryLocation::socket(value);
405 }
406 
memoryConfiguredSpeedInMhz(uint16_t value)407 uint16_t Dimm::memoryConfiguredSpeedInMhz(uint16_t value)
408 {
409     return sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::
410         memoryConfiguredSpeedInMhz(value);
411 }
412 
functional(bool value)413 bool Dimm::functional(bool value)
414 {
415     return sdbusplus::server::xyz::openbmc_project::state::decorator::
416         OperationalStatus::functional(value);
417 }
418 
419 } // namespace smbios
420 } // namespace phosphor
421