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