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