xref: /openbmc/dbus-sensors/src/nvidia-gpu/Inventory.cpp (revision fb64f063eda800ac7b1b604ede05d915c018147f)
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