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