blob: dc8bb92f7e72a95706629f6da5b9d87d2cc5d41a [file] [log] [blame]
Cheng C Yang8c3fab62019-12-19 00:51:06 +08001/*
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
kasunath634ec6a2022-07-25 15:34:17 -070021#include <boost/algorithm/string.hpp>
kasunath2eca4fe2022-08-17 17:30:07 -070022#include <phosphor-logging/elog-errors.hpp>
kasunath634ec6a2022-07-25 15:34:17 -070023
Tony Lee8f789c32024-07-10 20:01:43 +080024#include <fstream>
25#include <iostream>
Jayaprakash Mutyalaa1ff2442023-06-15 07:10:07 +000026#include <regex>
27
Cheng C Yang8c3fab62019-12-19 00:51:06 +080028namespace phosphor
29{
30namespace smbios
31{
32
John Edward Broadbentefd41542022-12-13 16:39:18 -080033#ifdef DIMM_ONLY_LOCATOR
34bool onlyDimmLocationCode = true;
35#else
36bool onlyDimmLocationCode = false;
37#endif
38
Cheng C Yang8c3fab62019-12-19 00:51:06 +080039using DeviceType =
Jason M. Bills33ae81f2023-04-26 09:06:08 -070040 sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::DeviceType;
Cheng C Yang8c3fab62019-12-19 00:51:06 +080041
kasunath2eca4fe2022-08-17 17:30:07 -070042using EccType =
Jason M. Bills33ae81f2023-04-26 09:06:08 -070043 sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::Ecc;
kasunath2eca4fe2022-08-17 17:30:07 -070044
Cheng C Yang8c3fab62019-12-19 00:51:06 +080045static constexpr uint16_t maxOldDimmSize = 0x7fff;
Tony Lee8f789c32024-07-10 20:01:43 +080046
47static constexpr const char* filename =
48 "/usr/share/smbios-mdr/memoryLocationTable.json";
49
Brandon Kim5a122a62023-05-04 04:25:03 +000050void Dimm::memoryInfoUpdate(uint8_t* smbiosTableStorage,
51 const std::string& motherboard)
Cheng C Yang8c3fab62019-12-19 00:51:06 +080052{
Brandon Kim5a122a62023-05-04 04:25:03 +000053 storage = smbiosTableStorage;
54 motherboardPath = motherboard;
55
Cheng C Yang2ca7a0f2019-12-19 10:46:42 +080056 uint8_t* dataIn = storage;
Cheng C Yang8c3fab62019-12-19 00:51:06 +080057
58 dataIn = getSMBIOSTypePtr(dataIn, memoryDeviceType);
59
60 if (dataIn == nullptr)
61 {
62 return;
63 }
64 for (uint8_t index = 0; index < dimmNum; index++)
65 {
66 dataIn = smbiosNextPtr(dataIn);
67 if (dataIn == nullptr)
68 {
69 return;
70 }
71 dataIn = getSMBIOSTypePtr(dataIn, memoryDeviceType);
72 if (dataIn == nullptr)
73 {
74 return;
75 }
76 }
77
Cheng C Yang2ca7a0f2019-12-19 10:46:42 +080078 auto memoryInfo = reinterpret_cast<struct MemoryInfo*>(dataIn);
Cheng C Yang8c3fab62019-12-19 00:51:06 +080079
80 memoryDataWidth(memoryInfo->dataWidth);
Joseph Fu410bbc22023-07-12 19:01:04 +080081 memoryTotalWidth(memoryInfo->totalWidth);
Cheng C Yang8c3fab62019-12-19 00:51:06 +080082
83 if (memoryInfo->size == maxOldDimmSize)
84 {
85 dimmSizeExt(memoryInfo->extendedSize);
86 }
87 else
88 {
89 dimmSize(memoryInfo->size);
90 }
Tom Tung39cc3682023-03-15 04:44:04 +080091 // If the size is 0, no memory device is installed in the socket.
92 const auto isDimmPresent = memoryInfo->size > 0;
93 present(isDimmPresent);
94 functional(isDimmPresent);
Cheng C Yang8c3fab62019-12-19 00:51:06 +080095
Konstantin Aladyshev744b35a2022-11-02 08:34:27 +000096 dimmDeviceLocator(memoryInfo->bankLocator, memoryInfo->deviceLocator,
97 memoryInfo->length, dataIn);
Cheng C Yang8c3fab62019-12-19 00:51:06 +080098 dimmType(memoryInfo->memoryType);
99 dimmTypeDetail(memoryInfo->typeDetail);
100 maxMemorySpeedInMhz(memoryInfo->speed);
101 dimmManufacturer(memoryInfo->manufacturer, memoryInfo->length, dataIn);
102 dimmSerialNum(memoryInfo->serialNum, memoryInfo->length, dataIn);
103 dimmPartNum(memoryInfo->partNum, memoryInfo->length, dataIn);
104 memoryAttributes(memoryInfo->attributes);
Jayaprakash Mutyalaa1ff2442023-06-15 07:10:07 +0000105 dimmMedia(memoryInfo->memoryTechnology);
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800106 memoryConfiguredSpeedInMhz(memoryInfo->confClockSpeed);
107
kasunath2eca4fe2022-08-17 17:30:07 -0700108 updateEccType(memoryInfo->phyArrayHandle);
109
Jie Yange7cf3192021-08-20 11:21:43 -0700110 if (!motherboardPath.empty())
111 {
112 std::vector<std::tuple<std::string, std::string, std::string>> assocs;
113 assocs.emplace_back("chassis", "memories", motherboardPath);
114 association::associations(assocs);
115 }
116
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800117 return;
118}
119
kasunath2eca4fe2022-08-17 17:30:07 -0700120void Dimm::updateEccType(uint16_t exPhyArrayHandle)
121{
122 uint8_t* dataIn = storage;
123
124 while (dataIn != nullptr)
125 {
126 dataIn = getSMBIOSTypePtr(dataIn, physicalMemoryArrayType);
127 if (dataIn == nullptr)
128 {
129 phosphor::logging::log<phosphor::logging::level::ERR>(
130 "Failed to get SMBIOS table type-16 data.");
131 return;
132 }
133
134 auto info = reinterpret_cast<struct PhysicalMemoryArrayInfo*>(dataIn);
135 if (info->handle == exPhyArrayHandle)
136 {
137 std::map<uint8_t, EccType>::const_iterator it =
138 dimmEccTypeMap.find(info->memoryErrorCorrection);
139 if (it == dimmEccTypeMap.end())
140 {
141 ecc(EccType::NoECC);
142 }
143 else
144 {
145 ecc(it->second);
146 }
147 return;
148 }
149
150 dataIn = smbiosNextPtr(dataIn);
151 }
152 phosphor::logging::log<phosphor::logging::level::ERR>(
153 "Failed find the corresponding SMBIOS table type-16 data for dimm:",
154 phosphor::logging::entry("DIMM:%d", dimmNum));
155}
156
157EccType Dimm::ecc(EccType value)
158{
Jason M. Bills33ae81f2023-04-26 09:06:08 -0700159 return sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::ecc(
kasunath2eca4fe2022-08-17 17:30:07 -0700160 value);
161}
162
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800163uint16_t Dimm::memoryDataWidth(uint16_t value)
164{
Jason M. Bills33ae81f2023-04-26 09:06:08 -0700165 return sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800166 memoryDataWidth(value);
167}
168
Joseph Fu410bbc22023-07-12 19:01:04 +0800169uint16_t Dimm::memoryTotalWidth(uint16_t value)
170{
171 return sdbusplus::xyz::openbmc_project::Inventory::Item::server::Dimm::
172 memoryTotalWidth(value);
173}
174
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800175static constexpr uint16_t baseNewVersionDimmSize = 0x8000;
176static constexpr uint16_t dimmSizeUnit = 1024;
177void Dimm::dimmSize(const uint16_t size)
178{
Joseph Fu0b1d9422023-03-31 17:47:12 +0800179 uint32_t result = size & maxOldDimmSize;
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800180 if (0 == (size & baseNewVersionDimmSize))
181 {
182 result = result * dimmSizeUnit;
183 }
184 memorySizeInKB(result);
185}
186
Joseph Fu0b1d9422023-03-31 17:47:12 +0800187void Dimm::dimmSizeExt(uint32_t size)
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800188{
189 size = size * dimmSizeUnit;
190 memorySizeInKB(size);
191}
192
Jason M. Billse7770992021-05-14 13:24:33 -0700193size_t Dimm::memorySizeInKB(size_t value)
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800194{
Jason M. Bills33ae81f2023-04-26 09:06:08 -0700195 return sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800196 memorySizeInKB(value);
197}
198
Konstantin Aladyshev744b35a2022-11-02 08:34:27 +0000199void Dimm::dimmDeviceLocator(const uint8_t bankLocatorPositionNum,
200 const uint8_t deviceLocatorPositionNum,
201 const uint8_t structLen, uint8_t* dataIn)
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800202{
Patrick Williams1d73dcc2024-08-16 15:21:42 -0400203 std::string deviceLocator =
204 positionToString(deviceLocatorPositionNum, structLen, dataIn);
205 std::string bankLocator =
206 positionToString(bankLocatorPositionNum, structLen, dataIn);
Konstantin Aladyshev744b35a2022-11-02 08:34:27 +0000207
208 std::string result;
John Edward Broadbentefd41542022-12-13 16:39:18 -0800209 if (bankLocator.empty() || onlyDimmLocationCode)
Konstantin Aladyshev744b35a2022-11-02 08:34:27 +0000210 {
John Edward Broadbentefd41542022-12-13 16:39:18 -0800211 result = deviceLocator;
Konstantin Aladyshev744b35a2022-11-02 08:34:27 +0000212 }
213 else
214 {
John Edward Broadbentefd41542022-12-13 16:39:18 -0800215 result = bankLocator + " " + deviceLocator;
Konstantin Aladyshev744b35a2022-11-02 08:34:27 +0000216 }
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800217
218 memoryDeviceLocator(result);
Jie Yang31720392021-07-22 21:45:45 -0700219
220 locationCode(result);
Jayaprakash Mutyalaa1ff2442023-06-15 07:10:07 +0000221 const std::string substrCpu = "CPU";
222 auto cpuPos = deviceLocator.find(substrCpu);
223
Tony Lee8f789c32024-07-10 20:01:43 +0800224 auto data = parseConfigFile();
225
226 if (!data.empty())
Jayaprakash Mutyalaa1ff2442023-06-15 07:10:07 +0000227 {
Tony Lee8f789c32024-07-10 20:01:43 +0800228 auto it = data.find(deviceLocator);
229
230 if (it != data.end())
Jayaprakash Mutyalaa1ff2442023-06-15 07:10:07 +0000231 {
Tony Lee8f789c32024-07-10 20:01:43 +0800232 uint8_t memoryControllerValue =
233 it.value()["MemoryController"].get<uint8_t>();
234 uint8_t socketValue = it.value()["Socket"].get<uint8_t>();
235 uint8_t slotValue = it.value()["Slot"].get<uint8_t>();
236 uint8_t channelValue = it.value()["Channel"].get<uint8_t>();
237
238 socket(memoryControllerValue);
239 memoryController(socketValue);
240 slot(slotValue);
241 channel(channelValue);
Jayaprakash Mutyalaa1ff2442023-06-15 07:10:07 +0000242 }
Tony Lee8f789c32024-07-10 20:01:43 +0800243 else
Jayaprakash Mutyalaa1ff2442023-06-15 07:10:07 +0000244 {
Tony Lee8f789c32024-07-10 20:01:43 +0800245 socket(0);
246 memoryController(0);
247 slot(0);
248 channel(0);
Jayaprakash Mutyalaa1ff2442023-06-15 07:10:07 +0000249 phosphor::logging::log<phosphor::logging::level::ERR>(
Tony Lee8f789c32024-07-10 20:01:43 +0800250 "Failed find the corresponding table for dimm ",
251 phosphor::logging::entry("DIMM:%s", deviceLocator.c_str()));
252 }
253 }
254 else
255 {
256 if (cpuPos != std::string::npos)
257 {
258 std::string socketString =
259 deviceLocator.substr(cpuPos + substrCpu.length(), 1);
260 try
261 {
262 uint8_t socketNum =
263 static_cast<uint8_t>(std::stoi(socketString) + 1);
264 socket(socketNum);
265 }
266 catch (const sdbusplus::exception_t& ex)
267 {
268 phosphor::logging::log<phosphor::logging::level::ERR>(
269 "std::stoi operation failed ",
270 phosphor::logging::entry("ERROR=%s", ex.what()));
271 }
Jayaprakash Mutyalaa1ff2442023-06-15 07:10:07 +0000272 }
273 }
274
275 const std::string substrDimm = "DIMM";
276 auto dimmPos = deviceLocator.find(substrDimm);
277
278 if (dimmPos != std::string::npos)
279 {
280 std::string slotString =
281 deviceLocator.substr(dimmPos + substrDimm.length() + 1);
282 /* slotString is extracted from substrDimm (DIMM_A) if slotString is
283 * single alphabet like A, B , C.. then assign ASCII value of slotString
284 * to slot */
285 if ((std::regex_match(slotString, std::regex("^[A-Za-z]+$"))) &&
286 (slotString.length() == 1))
287 {
288 slot(static_cast<uint8_t>(toupper(slotString[0])));
289 }
290 }
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800291}
292
293std::string Dimm::memoryDeviceLocator(std::string value)
294{
Jason M. Bills33ae81f2023-04-26 09:06:08 -0700295 return sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800296 memoryDeviceLocator(value);
297}
298
299void Dimm::dimmType(const uint8_t type)
300{
301 std::map<uint8_t, DeviceType>::const_iterator it = dimmTypeTable.find(type);
302 if (it == dimmTypeTable.end())
303 {
304 memoryType(DeviceType::Unknown);
305 }
306 else
307 {
308 memoryType(it->second);
309 }
310}
311
312DeviceType Dimm::memoryType(DeviceType value)
313{
Jason M. Bills33ae81f2023-04-26 09:06:08 -0700314 return sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800315 memoryType(value);
316}
317
Jayaprakash Mutyalaa1ff2442023-06-15 07:10:07 +0000318void Dimm::dimmMedia(const uint8_t type)
319{
320 std::map<uint8_t, MemoryTechType>::const_iterator it =
321 dimmMemoryTechTypeMap.find(type);
322 if (it == dimmMemoryTechTypeMap.end())
323 {
324 memoryMedia(MemoryTechType::Unknown);
325 }
326 else
327 {
328 memoryMedia(it->second);
329 }
330}
331
332MemoryTechType Dimm::memoryMedia(MemoryTechType value)
333{
334 return sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::
335 memoryMedia(value);
336}
337
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800338void Dimm::dimmTypeDetail(uint16_t detail)
339{
340 std::string result;
341 for (uint8_t index = 0; index < (8 * sizeof(detail)); index++)
342 {
343 if (detail & 0x01)
344 {
345 result += detailTable[index];
346 }
347 detail >>= 1;
348 }
349 memoryTypeDetail(result);
350}
351
352std::string Dimm::memoryTypeDetail(std::string value)
353{
Jason M. Bills33ae81f2023-04-26 09:06:08 -0700354 return sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800355 memoryTypeDetail(value);
356}
357
358uint16_t Dimm::maxMemorySpeedInMhz(uint16_t value)
359{
Jason M. Bills33ae81f2023-04-26 09:06:08 -0700360 return sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800361 maxMemorySpeedInMhz(value);
362}
363
364void Dimm::dimmManufacturer(const uint8_t positionNum, const uint8_t structLen,
Cheng C Yang2ca7a0f2019-12-19 10:46:42 +0800365 uint8_t* dataIn)
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800366{
367 std::string result = positionToString(positionNum, structLen, dataIn);
368
Joshi-Mansi33c948a2021-03-20 00:58:50 +0530369 if (result == "NO DIMM")
370 {
Joshi-Mansi33c948a2021-03-20 00:58:50 +0530371 // No dimm presence so making manufacturer value as "" (instead of
372 // NO DIMM - as there won't be any manufacturer for DIMM which is not
373 // present).
374 result = "";
375 }
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800376 manufacturer(result);
377}
378
379std::string Dimm::manufacturer(std::string value)
380{
Jason M. Bills33ae81f2023-04-26 09:06:08 -0700381 return sdbusplus::server::xyz::openbmc_project::inventory::decorator::
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800382 Asset::manufacturer(value);
383}
384
Joshi-Mansi33c948a2021-03-20 00:58:50 +0530385bool Dimm::present(bool value)
386{
Jason M. Bills33ae81f2023-04-26 09:06:08 -0700387 return sdbusplus::server::xyz::openbmc_project::inventory::Item::present(
Joshi-Mansi33c948a2021-03-20 00:58:50 +0530388 value);
389}
390
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800391void Dimm::dimmSerialNum(const uint8_t positionNum, const uint8_t structLen,
Cheng C Yang2ca7a0f2019-12-19 10:46:42 +0800392 uint8_t* dataIn)
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800393{
394 std::string result = positionToString(positionNum, structLen, dataIn);
395
396 serialNumber(result);
397}
398
399std::string Dimm::serialNumber(std::string value)
400{
Jason M. Bills33ae81f2023-04-26 09:06:08 -0700401 return sdbusplus::server::xyz::openbmc_project::inventory::decorator::
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800402 Asset::serialNumber(value);
403}
404
405void Dimm::dimmPartNum(const uint8_t positionNum, const uint8_t structLen,
Cheng C Yang2ca7a0f2019-12-19 10:46:42 +0800406 uint8_t* dataIn)
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800407{
408 std::string result = positionToString(positionNum, structLen, dataIn);
409
kasunath634ec6a2022-07-25 15:34:17 -0700410 // Part number could contain spaces at the end. Eg: "abcd123 ". Since its
411 // unnecessary, we should remove them.
412 boost::algorithm::trim_right(result);
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800413 partNumber(result);
414}
415
416std::string Dimm::partNumber(std::string value)
417{
Jason M. Bills33ae81f2023-04-26 09:06:08 -0700418 return sdbusplus::server::xyz::openbmc_project::inventory::decorator::
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800419 Asset::partNumber(value);
420}
421
Jie Yang31720392021-07-22 21:45:45 -0700422std::string Dimm::locationCode(std::string value)
423{
Jason M. Bills33ae81f2023-04-26 09:06:08 -0700424 return sdbusplus::server::xyz::openbmc_project::inventory::decorator::
Jie Yang31720392021-07-22 21:45:45 -0700425 LocationCode::locationCode(value);
426}
427
George Liu036374a2023-06-15 08:47:46 +0800428size_t Dimm::memoryAttributes(size_t value)
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800429{
Jason M. Bills33ae81f2023-04-26 09:06:08 -0700430 return sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800431 memoryAttributes(value);
432}
433
Jayaprakash Mutyalaa1ff2442023-06-15 07:10:07 +0000434uint8_t Dimm::slot(uint8_t value)
435{
436 return sdbusplus::server::xyz::openbmc_project::inventory::item::dimm::
437 MemoryLocation::slot(value);
438}
439
Tony Lee8f789c32024-07-10 20:01:43 +0800440uint8_t Dimm::memoryController(uint8_t value)
441{
442 return sdbusplus::server::xyz::openbmc_project::inventory::item::dimm::
443 MemoryLocation::memoryController(value);
444}
445
446uint8_t Dimm::channel(uint8_t value)
447{
448 return sdbusplus::server::xyz::openbmc_project::inventory::item::dimm::
449 MemoryLocation::channel(value);
450}
451
Jayaprakash Mutyalaa1ff2442023-06-15 07:10:07 +0000452uint8_t Dimm::socket(uint8_t value)
453{
454 return sdbusplus::server::xyz::openbmc_project::inventory::item::dimm::
455 MemoryLocation::socket(value);
456}
457
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800458uint16_t Dimm::memoryConfiguredSpeedInMhz(uint16_t value)
459{
Jason M. Bills33ae81f2023-04-26 09:06:08 -0700460 return sdbusplus::server::xyz::openbmc_project::inventory::item::Dimm::
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800461 memoryConfiguredSpeedInMhz(value);
462}
463
Tim Leedc469c72021-07-20 10:55:58 +0800464bool Dimm::functional(bool value)
465{
Jason M. Bills33ae81f2023-04-26 09:06:08 -0700466 return sdbusplus::server::xyz::openbmc_project::state::decorator::
Tim Leedc469c72021-07-20 10:55:58 +0800467 OperationalStatus::functional(value);
468}
469
Tony Lee8f789c32024-07-10 20:01:43 +0800470Json Dimm::parseConfigFile()
471{
472 std::ifstream memoryLocationFile(filename);
473
474 if (!memoryLocationFile.is_open())
475 {
476 phosphor::logging::log<phosphor::logging::level::ERR>(
477 "config JSON file not found, FILENAME ",
478 phosphor::logging::entry("%s", filename));
479 return {};
480 }
481
482 auto data = Json::parse(memoryLocationFile, nullptr, false);
483 if (data.is_discarded())
484 {
485 phosphor::logging::log<phosphor::logging::level::ERR>(
486 "config readings JSON parser failure");
487 return {};
488 }
489
490 return data;
491}
492
Cheng C Yang8c3fab62019-12-19 00:51:06 +0800493} // namespace smbios
494} // namespace phosphor