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