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