10a88826fSRohit PAI #include "Inventory.hpp" 20a88826fSRohit PAI 30a88826fSRohit PAI #include "Utils.hpp" 40a88826fSRohit PAI 5*ada6baa9SRohit PAI #include <MctpRequester.hpp> 60a88826fSRohit PAI #include <NvidiaGpuMctpVdm.hpp> 7*ada6baa9SRohit PAI #include <OcpMctpVdm.hpp> 8*ada6baa9SRohit PAI #include <boost/asio/io_context.hpp> 90a88826fSRohit PAI #include <phosphor-logging/lg2.hpp> 100a88826fSRohit PAI #include <sdbusplus/asio/connection.hpp> 110a88826fSRohit PAI #include <sdbusplus/asio/object_server.hpp> 120a88826fSRohit PAI 13*ada6baa9SRohit PAI #include <cstdint> 140a88826fSRohit PAI #include <memory> 15*ada6baa9SRohit PAI #include <optional> 160a88826fSRohit PAI #include <string> 17*ada6baa9SRohit PAI #include <unordered_map> 18*ada6baa9SRohit PAI #include <variant> 190a88826fSRohit PAI 200a88826fSRohit PAI constexpr const char* inventoryPrefix = "/xyz/openbmc_project/inventory/"; 210a88826fSRohit PAI constexpr const char* acceleratorIfaceName = 220a88826fSRohit PAI "xyz.openbmc_project.Inventory.Item.Accelerator"; 23*ada6baa9SRohit PAI static constexpr const char* assetIfaceName = 24*ada6baa9SRohit PAI "xyz.openbmc_project.Inventory.Decorator.Asset"; 250a88826fSRohit PAI 260a88826fSRohit PAI Inventory::Inventory( 270a88826fSRohit PAI const std::shared_ptr<sdbusplus::asio::connection>& /*conn*/, 280a88826fSRohit PAI sdbusplus::asio::object_server& objectServer, 29*ada6baa9SRohit PAI const std::string& inventoryName, mctp::MctpRequester& mctpRequester, 30*ada6baa9SRohit PAI const gpu::DeviceIdentification deviceTypeIn, const uint8_t eid, 31*ada6baa9SRohit PAI boost::asio::io_context& io) : 32*ada6baa9SRohit PAI name(escapeName(inventoryName)), mctpRequester(mctpRequester), 33*ada6baa9SRohit PAI deviceType(deviceTypeIn), eid(eid), retryTimer(io) 340a88826fSRohit PAI { 35*ada6baa9SRohit PAI requestBuffer = std::make_shared<InventoryRequestBuffer>(); 36*ada6baa9SRohit PAI responseBuffer = std::make_shared<InventoryResponseBuffer>(); 37*ada6baa9SRohit PAI 380a88826fSRohit PAI std::string path = inventoryPrefix + name; 39*ada6baa9SRohit PAI assetIface = objectServer.add_interface(path, assetIfaceName); 40*ada6baa9SRohit PAI assetIface->register_property("Manufacturer", std::string("NVIDIA")); 41*ada6baa9SRohit PAI // Register properties which need to be fetched from the device 42*ada6baa9SRohit PAI registerProperty(gpu::InventoryPropertyId::SERIAL_NUMBER, assetIface, 43*ada6baa9SRohit PAI "SerialNumber"); 44*ada6baa9SRohit PAI registerProperty(gpu::InventoryPropertyId::BOARD_PART_NUMBER, assetIface, 45*ada6baa9SRohit PAI "PartNumber"); 46*ada6baa9SRohit PAI assetIface->initialize(); 47*ada6baa9SRohit PAI 48*ada6baa9SRohit PAI // Static properties 49*ada6baa9SRohit PAI if (deviceType == gpu::DeviceIdentification::DEVICE_GPU) 500a88826fSRohit PAI { 510a88826fSRohit PAI acceleratorInterface = 520a88826fSRohit PAI objectServer.add_interface(path, acceleratorIfaceName); 530a88826fSRohit PAI acceleratorInterface->register_property("Type", std::string("GPU")); 540a88826fSRohit PAI acceleratorInterface->initialize(); 550a88826fSRohit PAI } 56*ada6baa9SRohit PAI 57*ada6baa9SRohit PAI processNextProperty(); 58*ada6baa9SRohit PAI } 59*ada6baa9SRohit PAI 60*ada6baa9SRohit PAI void Inventory::registerProperty( 61*ada6baa9SRohit PAI gpu::InventoryPropertyId propertyId, 62*ada6baa9SRohit PAI const std::shared_ptr<sdbusplus::asio::dbus_interface>& interface, 63*ada6baa9SRohit PAI const std::string& propertyName) 64*ada6baa9SRohit PAI { 65*ada6baa9SRohit PAI if (interface) 66*ada6baa9SRohit PAI { 67*ada6baa9SRohit PAI interface->register_property(propertyName, std::string{}); 68*ada6baa9SRohit PAI properties[propertyId] = {interface, propertyName, 0, true}; 69*ada6baa9SRohit PAI } 70*ada6baa9SRohit PAI } 71*ada6baa9SRohit PAI 72*ada6baa9SRohit PAI void Inventory::processInventoryProperty(gpu::InventoryPropertyId propertyId) 73*ada6baa9SRohit PAI { 74*ada6baa9SRohit PAI auto it = properties.find(propertyId); 75*ada6baa9SRohit PAI if (it != properties.end()) 76*ada6baa9SRohit PAI { 77*ada6baa9SRohit PAI markPropertyPending(it); 78*ada6baa9SRohit PAI std::optional<gpu::InventoryPropertyId> nextProperty = 79*ada6baa9SRohit PAI getNextPendingProperty(); 80*ada6baa9SRohit PAI if (nextProperty && *nextProperty == propertyId) 81*ada6baa9SRohit PAI { 82*ada6baa9SRohit PAI processNextProperty(); 83*ada6baa9SRohit PAI } 84*ada6baa9SRohit PAI } 85*ada6baa9SRohit PAI } 86*ada6baa9SRohit PAI 87*ada6baa9SRohit PAI void Inventory::markPropertyPending( 88*ada6baa9SRohit PAI std::unordered_map<gpu::InventoryPropertyId, PropertyInfo>::iterator it) 89*ada6baa9SRohit PAI { 90*ada6baa9SRohit PAI it->second.isPending = true; 91*ada6baa9SRohit PAI it->second.retryCount = 0; 92*ada6baa9SRohit PAI } 93*ada6baa9SRohit PAI 94*ada6baa9SRohit PAI void Inventory::markPropertyProcessed( 95*ada6baa9SRohit PAI std::unordered_map<gpu::InventoryPropertyId, PropertyInfo>::iterator it) 96*ada6baa9SRohit PAI { 97*ada6baa9SRohit PAI it->second.isPending = false; 98*ada6baa9SRohit PAI } 99*ada6baa9SRohit PAI 100*ada6baa9SRohit PAI std::optional<gpu::InventoryPropertyId> Inventory::getNextPendingProperty() 101*ada6baa9SRohit PAI const 102*ada6baa9SRohit PAI { 103*ada6baa9SRohit PAI for (const auto& [propertyId, info] : properties) 104*ada6baa9SRohit PAI { 105*ada6baa9SRohit PAI if (info.isPending) 106*ada6baa9SRohit PAI { 107*ada6baa9SRohit PAI return propertyId; 108*ada6baa9SRohit PAI } 109*ada6baa9SRohit PAI } 110*ada6baa9SRohit PAI return std::nullopt; 111*ada6baa9SRohit PAI } 112*ada6baa9SRohit PAI 113*ada6baa9SRohit PAI void Inventory::sendInventoryPropertyRequest( 114*ada6baa9SRohit PAI gpu::InventoryPropertyId propertyId) 115*ada6baa9SRohit PAI { 116*ada6baa9SRohit PAI int rc = gpu::encodeGetInventoryInformationRequest( 117*ada6baa9SRohit PAI 0, static_cast<uint8_t>(propertyId), *requestBuffer); 118*ada6baa9SRohit PAI if (rc != 0) 1190a88826fSRohit PAI { 1200a88826fSRohit PAI lg2::error( 121*ada6baa9SRohit PAI "Failed to encode property ID {PROP_ID} request for {NAME}: rc={RC}", 122*ada6baa9SRohit PAI "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name, "RC", 123*ada6baa9SRohit PAI rc); 124*ada6baa9SRohit PAI return; 1250a88826fSRohit PAI } 126*ada6baa9SRohit PAI 127*ada6baa9SRohit PAI lg2::info( 128*ada6baa9SRohit PAI "Sending inventory request for property ID {PROP_ID} to EID {EID} for {NAME}", 129*ada6baa9SRohit PAI "PROP_ID", static_cast<uint8_t>(propertyId), "EID", eid, "NAME", name); 130*ada6baa9SRohit PAI 131*ada6baa9SRohit PAI mctpRequester.sendRecvMsg(eid, *requestBuffer, *responseBuffer, 132*ada6baa9SRohit PAI [this, propertyId](int sendRecvMsgResult) { 133*ada6baa9SRohit PAI this->handleInventoryPropertyResponse( 134*ada6baa9SRohit PAI propertyId, sendRecvMsgResult); 135*ada6baa9SRohit PAI }); 136*ada6baa9SRohit PAI } 137*ada6baa9SRohit PAI 138*ada6baa9SRohit PAI void Inventory::handleInventoryPropertyResponse( 139*ada6baa9SRohit PAI gpu::InventoryPropertyId propertyId, int sendRecvMsgResult) 140*ada6baa9SRohit PAI { 141*ada6baa9SRohit PAI auto it = properties.find(propertyId); 142*ada6baa9SRohit PAI if (it == properties.end()) 143*ada6baa9SRohit PAI { 144*ada6baa9SRohit PAI lg2::error("Property ID {PROP_ID} for {NAME} not found", "PROP_ID", 145*ada6baa9SRohit PAI static_cast<uint8_t>(propertyId), "NAME", name); 146*ada6baa9SRohit PAI processNextProperty(); 147*ada6baa9SRohit PAI return; 148*ada6baa9SRohit PAI } 149*ada6baa9SRohit PAI 150*ada6baa9SRohit PAI bool success = false; 151*ada6baa9SRohit PAI if (sendRecvMsgResult == 0) 152*ada6baa9SRohit PAI { 153*ada6baa9SRohit PAI ocp::accelerator_management::CompletionCode cc{}; 154*ada6baa9SRohit PAI uint16_t reasonCode = 0; 155*ada6baa9SRohit PAI gpu::InventoryValue info; 156*ada6baa9SRohit PAI int rc = gpu::decodeGetInventoryInformationResponse( 157*ada6baa9SRohit PAI *responseBuffer, cc, reasonCode, propertyId, info); 158*ada6baa9SRohit PAI 159*ada6baa9SRohit PAI lg2::info( 160*ada6baa9SRohit PAI "Response for property ID {PROP_ID} from {NAME}, sendRecvMsgResult: {RESULT}, decode_rc: {RC}, completion_code: {CC}, reason_code: {REASON}", 161*ada6baa9SRohit PAI "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name, "RESULT", 162*ada6baa9SRohit PAI sendRecvMsgResult, "RC", rc, "CC", static_cast<uint8_t>(cc), 163*ada6baa9SRohit PAI "REASON", reasonCode); 164*ada6baa9SRohit PAI 165*ada6baa9SRohit PAI if (rc == 0 && 166*ada6baa9SRohit PAI cc == ocp::accelerator_management::CompletionCode::SUCCESS && 167*ada6baa9SRohit PAI std::holds_alternative<std::string>(info)) 168*ada6baa9SRohit PAI { 169*ada6baa9SRohit PAI std::string value = std::get<std::string>(info); 170*ada6baa9SRohit PAI it->second.interface->set_property(it->second.propertyName, value); 171*ada6baa9SRohit PAI lg2::info( 172*ada6baa9SRohit PAI "Successfully received property ID {PROP_ID} for {NAME} with value: {VALUE}", 173*ada6baa9SRohit PAI "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name, 174*ada6baa9SRohit PAI "VALUE", value); 175*ada6baa9SRohit PAI success = true; 176*ada6baa9SRohit PAI } 177*ada6baa9SRohit PAI } 178*ada6baa9SRohit PAI 179*ada6baa9SRohit PAI if (!success) 180*ada6baa9SRohit PAI { 181*ada6baa9SRohit PAI it->second.retryCount++; 182*ada6baa9SRohit PAI if (it->second.retryCount >= maxRetryAttempts) 183*ada6baa9SRohit PAI { 184*ada6baa9SRohit PAI lg2::error( 185*ada6baa9SRohit PAI "Property ID {PROP_ID} for {NAME} failed after {ATTEMPTS} attempts", 186*ada6baa9SRohit PAI "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name, 187*ada6baa9SRohit PAI "ATTEMPTS", maxRetryAttempts); 188*ada6baa9SRohit PAI markPropertyProcessed(it); 189*ada6baa9SRohit PAI } 190*ada6baa9SRohit PAI else 191*ada6baa9SRohit PAI { 192*ada6baa9SRohit PAI retryTimer.expires_after(retryDelay); 193*ada6baa9SRohit PAI retryTimer.async_wait([this](const boost::system::error_code& ec) { 194*ada6baa9SRohit PAI if (ec) 195*ada6baa9SRohit PAI { 196*ada6baa9SRohit PAI lg2::error("Retry timer error for {NAME}: {ERROR}", "NAME", 197*ada6baa9SRohit PAI name, "ERROR", ec.message()); 198*ada6baa9SRohit PAI return; 199*ada6baa9SRohit PAI } 200*ada6baa9SRohit PAI this->processNextProperty(); 201*ada6baa9SRohit PAI }); 202*ada6baa9SRohit PAI return; 203*ada6baa9SRohit PAI } 204*ada6baa9SRohit PAI } 205*ada6baa9SRohit PAI else 206*ada6baa9SRohit PAI { 207*ada6baa9SRohit PAI markPropertyProcessed(it); 208*ada6baa9SRohit PAI } 209*ada6baa9SRohit PAI 210*ada6baa9SRohit PAI processNextProperty(); 211*ada6baa9SRohit PAI } 212*ada6baa9SRohit PAI 213*ada6baa9SRohit PAI void Inventory::processNextProperty() 214*ada6baa9SRohit PAI { 215*ada6baa9SRohit PAI std::optional<gpu::InventoryPropertyId> nextProperty = 216*ada6baa9SRohit PAI getNextPendingProperty(); 217*ada6baa9SRohit PAI if (nextProperty) 218*ada6baa9SRohit PAI { 219*ada6baa9SRohit PAI sendInventoryPropertyRequest(*nextProperty); 220*ada6baa9SRohit PAI } 221*ada6baa9SRohit PAI else 222*ada6baa9SRohit PAI { 223*ada6baa9SRohit PAI lg2::info("No pending properties found to process for {NAME}", "NAME", 224*ada6baa9SRohit PAI name); 2250a88826fSRohit PAI } 2260a88826fSRohit PAI } 227