| Rohit PAI | 0a88826 | 2025-06-11 08:52:29 +0530 | [diff] [blame] | 1 | #include "Inventory.hpp" | 
|  | 2 |  | 
|  | 3 | #include "Utils.hpp" | 
|  | 4 |  | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 5 | #include <MctpRequester.hpp> | 
| Rohit PAI | 0a88826 | 2025-06-11 08:52:29 +0530 | [diff] [blame] | 6 | #include <NvidiaGpuMctpVdm.hpp> | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 7 | #include <OcpMctpVdm.hpp> | 
|  | 8 | #include <boost/asio/io_context.hpp> | 
| Rohit PAI | fb64f06 | 2025-06-13 18:20:02 +0530 | [diff] [blame] | 9 | #include <boost/uuid/uuid.hpp> | 
|  | 10 | #include <boost/uuid/uuid_io.hpp> | 
| Rohit PAI | 0a88826 | 2025-06-11 08:52:29 +0530 | [diff] [blame] | 11 | #include <phosphor-logging/lg2.hpp> | 
|  | 12 | #include <sdbusplus/asio/connection.hpp> | 
|  | 13 | #include <sdbusplus/asio/object_server.hpp> | 
|  | 14 |  | 
| Rohit PAI | fb64f06 | 2025-06-13 18:20:02 +0530 | [diff] [blame] | 15 | #include <algorithm> | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 16 | #include <cstdint> | 
| Rohit PAI | 0a88826 | 2025-06-11 08:52:29 +0530 | [diff] [blame] | 17 | #include <memory> | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 18 | #include <optional> | 
| Marc Olberding | d0125c9 | 2025-10-08 14:37:19 -0700 | [diff] [blame] | 19 | #include <span> | 
| Rohit PAI | 0a88826 | 2025-06-11 08:52:29 +0530 | [diff] [blame] | 20 | #include <string> | 
| Marc Olberding | d0125c9 | 2025-10-08 14:37:19 -0700 | [diff] [blame] | 21 | #include <system_error> | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 22 | #include <unordered_map> | 
|  | 23 | #include <variant> | 
| Rohit PAI | fb64f06 | 2025-06-13 18:20:02 +0530 | [diff] [blame] | 24 | #include <vector> | 
| Rohit PAI | 0a88826 | 2025-06-11 08:52:29 +0530 | [diff] [blame] | 25 |  | 
|  | 26 | constexpr const char* inventoryPrefix = "/xyz/openbmc_project/inventory/"; | 
|  | 27 | constexpr const char* acceleratorIfaceName = | 
|  | 28 | "xyz.openbmc_project.Inventory.Item.Accelerator"; | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 29 | static constexpr const char* assetIfaceName = | 
|  | 30 | "xyz.openbmc_project.Inventory.Decorator.Asset"; | 
| Rohit PAI | fb64f06 | 2025-06-13 18:20:02 +0530 | [diff] [blame] | 31 | static constexpr const char* uuidIfaceName = "xyz.openbmc_project.Common.UUID"; | 
| Rohit PAI | 0ad5710 | 2025-06-13 19:29:20 +0530 | [diff] [blame] | 32 | static constexpr const char* revisionIfaceName = | 
|  | 33 | "xyz.openbmc_project.Inventory.Decorator.Revision"; | 
| Rohit PAI | 0a88826 | 2025-06-11 08:52:29 +0530 | [diff] [blame] | 34 |  | 
|  | 35 | Inventory::Inventory( | 
|  | 36 | const std::shared_ptr<sdbusplus::asio::connection>& /*conn*/, | 
|  | 37 | sdbusplus::asio::object_server& objectServer, | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 38 | const std::string& inventoryName, mctp::MctpRequester& mctpRequester, | 
|  | 39 | const gpu::DeviceIdentification deviceTypeIn, const uint8_t eid, | 
|  | 40 | boost::asio::io_context& io) : | 
|  | 41 | name(escapeName(inventoryName)), mctpRequester(mctpRequester), | 
|  | 42 | deviceType(deviceTypeIn), eid(eid), retryTimer(io) | 
| Rohit PAI | 0a88826 | 2025-06-11 08:52:29 +0530 | [diff] [blame] | 43 | { | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 44 | std::string path = inventoryPrefix + name; | 
| Rohit PAI | fb64f06 | 2025-06-13 18:20:02 +0530 | [diff] [blame] | 45 |  | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 46 | assetIface = objectServer.add_interface(path, assetIfaceName); | 
|  | 47 | assetIface->register_property("Manufacturer", std::string("NVIDIA")); | 
|  | 48 | // Register properties which need to be fetched from the device | 
|  | 49 | registerProperty(gpu::InventoryPropertyId::SERIAL_NUMBER, assetIface, | 
|  | 50 | "SerialNumber"); | 
|  | 51 | registerProperty(gpu::InventoryPropertyId::BOARD_PART_NUMBER, assetIface, | 
|  | 52 | "PartNumber"); | 
| Rohit PAI | 0ad5710 | 2025-06-13 19:29:20 +0530 | [diff] [blame] | 53 | registerProperty(gpu::InventoryPropertyId::MARKETING_NAME, assetIface, | 
|  | 54 | "Model"); | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 55 | assetIface->initialize(); | 
|  | 56 |  | 
| Rohit PAI | fb64f06 | 2025-06-13 18:20:02 +0530 | [diff] [blame] | 57 | uuidInterface = objectServer.add_interface(path, uuidIfaceName); | 
|  | 58 | registerProperty(gpu::InventoryPropertyId::DEVICE_GUID, uuidInterface, | 
|  | 59 | "UUID"); | 
|  | 60 | uuidInterface->initialize(); | 
|  | 61 |  | 
| Rohit PAI | 0ad5710 | 2025-06-13 19:29:20 +0530 | [diff] [blame] | 62 | revisionIface = objectServer.add_interface(path, revisionIfaceName); | 
|  | 63 | registerProperty(gpu::InventoryPropertyId::DEVICE_PART_NUMBER, | 
|  | 64 | revisionIface, "Version"); | 
|  | 65 | revisionIface->initialize(); | 
|  | 66 |  | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 67 | // Static properties | 
| Rohit PAI | 0a88826 | 2025-06-11 08:52:29 +0530 | [diff] [blame] | 68 | if (deviceType == gpu::DeviceIdentification::DEVICE_GPU) | 
|  | 69 | { | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 70 | acceleratorInterface = | 
|  | 71 | objectServer.add_interface(path, acceleratorIfaceName); | 
|  | 72 | acceleratorInterface->register_property("Type", std::string("GPU")); | 
|  | 73 | acceleratorInterface->initialize(); | 
|  | 74 | } | 
| Marc Olberding | ac92073 | 2025-09-28 21:56:54 -0700 | [diff] [blame^] | 75 | } | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 76 |  | 
| Marc Olberding | ac92073 | 2025-09-28 21:56:54 -0700 | [diff] [blame^] | 77 | void Inventory::init() | 
|  | 78 | { | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 79 | processNextProperty(); | 
|  | 80 | } | 
|  | 81 |  | 
|  | 82 | void Inventory::registerProperty( | 
|  | 83 | gpu::InventoryPropertyId propertyId, | 
|  | 84 | const std::shared_ptr<sdbusplus::asio::dbus_interface>& interface, | 
|  | 85 | const std::string& propertyName) | 
|  | 86 | { | 
|  | 87 | if (interface) | 
|  | 88 | { | 
|  | 89 | interface->register_property(propertyName, std::string{}); | 
|  | 90 | properties[propertyId] = {interface, propertyName, 0, true}; | 
|  | 91 | } | 
|  | 92 | } | 
|  | 93 |  | 
|  | 94 | void Inventory::processInventoryProperty(gpu::InventoryPropertyId propertyId) | 
|  | 95 | { | 
|  | 96 | auto it = properties.find(propertyId); | 
|  | 97 | if (it != properties.end()) | 
|  | 98 | { | 
|  | 99 | markPropertyPending(it); | 
|  | 100 | std::optional<gpu::InventoryPropertyId> nextProperty = | 
|  | 101 | getNextPendingProperty(); | 
|  | 102 | if (nextProperty && *nextProperty == propertyId) | 
| Rohit PAI | 0a88826 | 2025-06-11 08:52:29 +0530 | [diff] [blame] | 103 | { | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 104 | processNextProperty(); | 
| Rohit PAI | 0a88826 | 2025-06-11 08:52:29 +0530 | [diff] [blame] | 105 | } | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 106 | } | 
|  | 107 | } | 
|  | 108 |  | 
|  | 109 | void Inventory::markPropertyPending( | 
|  | 110 | std::unordered_map<gpu::InventoryPropertyId, PropertyInfo>::iterator it) | 
|  | 111 | { | 
|  | 112 | it->second.isPending = true; | 
|  | 113 | it->second.retryCount = 0; | 
|  | 114 | } | 
|  | 115 |  | 
|  | 116 | void Inventory::markPropertyProcessed( | 
|  | 117 | std::unordered_map<gpu::InventoryPropertyId, PropertyInfo>::iterator it) | 
|  | 118 | { | 
|  | 119 | it->second.isPending = false; | 
|  | 120 | } | 
|  | 121 |  | 
|  | 122 | std::optional<gpu::InventoryPropertyId> Inventory::getNextPendingProperty() | 
|  | 123 | const | 
|  | 124 | { | 
|  | 125 | for (const auto& [propertyId, info] : properties) | 
|  | 126 | { | 
|  | 127 | if (info.isPending) | 
|  | 128 | { | 
|  | 129 | return propertyId; | 
|  | 130 | } | 
|  | 131 | } | 
|  | 132 | return std::nullopt; | 
|  | 133 | } | 
|  | 134 |  | 
|  | 135 | void Inventory::sendInventoryPropertyRequest( | 
|  | 136 | gpu::InventoryPropertyId propertyId) | 
|  | 137 | { | 
|  | 138 | int rc = gpu::encodeGetInventoryInformationRequest( | 
| Marc Olberding | d0125c9 | 2025-10-08 14:37:19 -0700 | [diff] [blame] | 139 | 0, static_cast<uint8_t>(propertyId), requestBuffer); | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 140 | if (rc != 0) | 
|  | 141 | { | 
|  | 142 | lg2::error( | 
|  | 143 | "Failed to encode property ID {PROP_ID} request for {NAME}: rc={RC}", | 
|  | 144 | "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name, "RC", | 
|  | 145 | rc); | 
|  | 146 | return; | 
|  | 147 | } | 
|  | 148 |  | 
|  | 149 | lg2::info( | 
|  | 150 | "Sending inventory request for property ID {PROP_ID} to EID {EID} for {NAME}", | 
|  | 151 | "PROP_ID", static_cast<uint8_t>(propertyId), "EID", eid, "NAME", name); | 
|  | 152 |  | 
| Marc Olberding | d0125c9 | 2025-10-08 14:37:19 -0700 | [diff] [blame] | 153 | mctpRequester.sendRecvMsg( | 
|  | 154 | eid, requestBuffer, | 
|  | 155 | [this, propertyId](const std::error_code& result, | 
|  | 156 | std::span<const uint8_t> buffer) { | 
|  | 157 | this->handleInventoryPropertyResponse(propertyId, result, buffer); | 
|  | 158 | }); | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 159 | } | 
|  | 160 |  | 
|  | 161 | void Inventory::handleInventoryPropertyResponse( | 
| Marc Olberding | d0125c9 | 2025-10-08 14:37:19 -0700 | [diff] [blame] | 162 | gpu::InventoryPropertyId propertyId, const std::error_code& ec, | 
|  | 163 | std::span<const uint8_t> buffer) | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 164 | { | 
|  | 165 | auto it = properties.find(propertyId); | 
|  | 166 | if (it == properties.end()) | 
|  | 167 | { | 
|  | 168 | lg2::error("Property ID {PROP_ID} for {NAME} not found", "PROP_ID", | 
|  | 169 | static_cast<uint8_t>(propertyId), "NAME", name); | 
|  | 170 | processNextProperty(); | 
|  | 171 | return; | 
|  | 172 | } | 
|  | 173 |  | 
|  | 174 | bool success = false; | 
| Marc Olberding | d0125c9 | 2025-10-08 14:37:19 -0700 | [diff] [blame] | 175 | if (!ec) | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 176 | { | 
|  | 177 | ocp::accelerator_management::CompletionCode cc{}; | 
|  | 178 | uint16_t reasonCode = 0; | 
|  | 179 | gpu::InventoryValue info; | 
|  | 180 | int rc = gpu::decodeGetInventoryInformationResponse( | 
| Marc Olberding | d0125c9 | 2025-10-08 14:37:19 -0700 | [diff] [blame] | 181 | buffer, cc, reasonCode, propertyId, info); | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 182 |  | 
|  | 183 | lg2::info( | 
|  | 184 | "Response for property ID {PROP_ID} from {NAME}, sendRecvMsgResult: {RESULT}, decode_rc: {RC}, completion_code: {CC}, reason_code: {REASON}", | 
|  | 185 | "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name, "RESULT", | 
| Marc Olberding | d0125c9 | 2025-10-08 14:37:19 -0700 | [diff] [blame] | 186 | ec.message(), "RC", rc, "CC", static_cast<uint8_t>(cc), "REASON", | 
|  | 187 | reasonCode); | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 188 |  | 
|  | 189 | if (rc == 0 && | 
| Rohit PAI | fb64f06 | 2025-06-13 18:20:02 +0530 | [diff] [blame] | 190 | cc == ocp::accelerator_management::CompletionCode::SUCCESS) | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 191 | { | 
| Rohit PAI | fb64f06 | 2025-06-13 18:20:02 +0530 | [diff] [blame] | 192 | std::string value; | 
|  | 193 |  | 
|  | 194 | // Handle different property types based on property ID | 
|  | 195 | switch (propertyId) | 
|  | 196 | { | 
|  | 197 | case gpu::InventoryPropertyId::BOARD_PART_NUMBER: | 
|  | 198 | case gpu::InventoryPropertyId::SERIAL_NUMBER: | 
|  | 199 | case gpu::InventoryPropertyId::MARKETING_NAME: | 
|  | 200 | case gpu::InventoryPropertyId::DEVICE_PART_NUMBER: | 
|  | 201 | if (std::holds_alternative<std::string>(info)) | 
|  | 202 | { | 
|  | 203 | value = std::get<std::string>(info); | 
|  | 204 | } | 
|  | 205 | else | 
|  | 206 | { | 
|  | 207 | lg2::error( | 
|  | 208 | "Property ID {PROP_ID} for {NAME} expected string but got different type", | 
|  | 209 | "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", | 
|  | 210 | name); | 
|  | 211 | break; | 
|  | 212 | } | 
|  | 213 | break; | 
|  | 214 |  | 
|  | 215 | case gpu::InventoryPropertyId::DEVICE_GUID: | 
|  | 216 | if (std::holds_alternative<std::vector<uint8_t>>(info)) | 
|  | 217 | { | 
|  | 218 | const auto& guidBytes = | 
|  | 219 | std::get<std::vector<uint8_t>>(info); | 
|  | 220 | if (guidBytes.size() >= 16) | 
|  | 221 | { | 
|  | 222 | boost::uuids::uuid uuid; | 
|  | 223 | std::copy(guidBytes.begin(), guidBytes.begin() + 16, | 
|  | 224 | uuid.begin()); | 
|  | 225 | value = boost::uuids::to_string(uuid); | 
|  | 226 | } | 
|  | 227 | else | 
|  | 228 | { | 
|  | 229 | lg2::error( | 
|  | 230 | "Property ID {PROP_ID} for {NAME} GUID size {SIZE} is less than 16 bytes", | 
|  | 231 | "PROP_ID", static_cast<uint8_t>(propertyId), | 
|  | 232 | "NAME", name, "SIZE", guidBytes.size()); | 
|  | 233 | break; | 
|  | 234 | } | 
|  | 235 | } | 
|  | 236 | else | 
|  | 237 | { | 
|  | 238 | lg2::error( | 
|  | 239 | "Property ID {PROP_ID} for {NAME} expected vector<uint8_t> but got different type", | 
|  | 240 | "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", | 
|  | 241 | name); | 
|  | 242 | break; | 
|  | 243 | } | 
|  | 244 | break; | 
|  | 245 |  | 
|  | 246 | default: | 
|  | 247 | lg2::error("Unsupported property ID {PROP_ID} for {NAME}", | 
|  | 248 | "PROP_ID", static_cast<uint8_t>(propertyId), | 
|  | 249 | "NAME", name); | 
|  | 250 | break; | 
|  | 251 | } | 
|  | 252 |  | 
|  | 253 | if (!value.empty()) | 
|  | 254 | { | 
|  | 255 | it->second.interface->set_property(it->second.propertyName, | 
|  | 256 | value); | 
|  | 257 | lg2::info( | 
|  | 258 | "Successfully received property ID {PROP_ID} for {NAME} with value: {VALUE}", | 
|  | 259 | "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name, | 
|  | 260 | "VALUE", value); | 
|  | 261 | success = true; | 
|  | 262 | } | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 263 | } | 
|  | 264 | } | 
|  | 265 |  | 
|  | 266 | if (!success) | 
|  | 267 | { | 
|  | 268 | it->second.retryCount++; | 
|  | 269 | if (it->second.retryCount >= maxRetryAttempts) | 
| Rohit PAI | 0a88826 | 2025-06-11 08:52:29 +0530 | [diff] [blame] | 270 | { | 
|  | 271 | lg2::error( | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 272 | "Property ID {PROP_ID} for {NAME} failed after {ATTEMPTS} attempts", | 
|  | 273 | "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name, | 
|  | 274 | "ATTEMPTS", maxRetryAttempts); | 
|  | 275 | markPropertyProcessed(it); | 
| Rohit PAI | 0a88826 | 2025-06-11 08:52:29 +0530 | [diff] [blame] | 276 | } | 
| Rohit PAI | ada6baa | 2025-07-01 18:26:19 +0530 | [diff] [blame] | 277 | else | 
|  | 278 | { | 
|  | 279 | retryTimer.expires_after(retryDelay); | 
|  | 280 | retryTimer.async_wait([this](const boost::system::error_code& ec) { | 
|  | 281 | if (ec) | 
|  | 282 | { | 
|  | 283 | lg2::error("Retry timer error for {NAME}: {ERROR}", "NAME", | 
|  | 284 | name, "ERROR", ec.message()); | 
|  | 285 | return; | 
|  | 286 | } | 
|  | 287 | this->processNextProperty(); | 
|  | 288 | }); | 
|  | 289 | return; | 
|  | 290 | } | 
|  | 291 | } | 
|  | 292 | else | 
|  | 293 | { | 
|  | 294 | markPropertyProcessed(it); | 
|  | 295 | } | 
|  | 296 |  | 
|  | 297 | processNextProperty(); | 
|  | 298 | } | 
|  | 299 |  | 
|  | 300 | void Inventory::processNextProperty() | 
|  | 301 | { | 
|  | 302 | std::optional<gpu::InventoryPropertyId> nextProperty = | 
|  | 303 | getNextPendingProperty(); | 
|  | 304 | if (nextProperty) | 
|  | 305 | { | 
|  | 306 | sendInventoryPropertyRequest(*nextProperty); | 
|  | 307 | } | 
|  | 308 | else | 
|  | 309 | { | 
|  | 310 | lg2::info("No pending properties found to process for {NAME}", "NAME", | 
|  | 311 | name); | 
| Rohit PAI | 0a88826 | 2025-06-11 08:52:29 +0530 | [diff] [blame] | 312 | } | 
|  | 313 | } |