blob: 6796a3230a9584231a940f8416f9c5668c401b7a [file] [log] [blame]
Rohit PAI0a888262025-06-11 08:52:29 +05301#include "Inventory.hpp"
2
3#include "Utils.hpp"
4
Rohit PAIada6baa2025-07-01 18:26:19 +05305#include <MctpRequester.hpp>
Rohit PAI0a888262025-06-11 08:52:29 +05306#include <NvidiaGpuMctpVdm.hpp>
Rohit PAIada6baa2025-07-01 18:26:19 +05307#include <OcpMctpVdm.hpp>
8#include <boost/asio/io_context.hpp>
Rohit PAIfb64f062025-06-13 18:20:02 +05309#include <boost/uuid/uuid.hpp>
10#include <boost/uuid/uuid_io.hpp>
Rohit PAI0a888262025-06-11 08:52:29 +053011#include <phosphor-logging/lg2.hpp>
12#include <sdbusplus/asio/connection.hpp>
13#include <sdbusplus/asio/object_server.hpp>
14
Rohit PAIfb64f062025-06-13 18:20:02 +053015#include <algorithm>
Rohit PAIada6baa2025-07-01 18:26:19 +053016#include <cstdint>
Rohit PAI0a888262025-06-11 08:52:29 +053017#include <memory>
Rohit PAIada6baa2025-07-01 18:26:19 +053018#include <optional>
Marc Olberdingd0125c92025-10-08 14:37:19 -070019#include <span>
Rohit PAI0a888262025-06-11 08:52:29 +053020#include <string>
Marc Olberdingd0125c92025-10-08 14:37:19 -070021#include <system_error>
Rohit PAIada6baa2025-07-01 18:26:19 +053022#include <unordered_map>
23#include <variant>
Rohit PAIfb64f062025-06-13 18:20:02 +053024#include <vector>
Rohit PAI0a888262025-06-11 08:52:29 +053025
26constexpr const char* inventoryPrefix = "/xyz/openbmc_project/inventory/";
27constexpr const char* acceleratorIfaceName =
28 "xyz.openbmc_project.Inventory.Item.Accelerator";
Rohit PAIada6baa2025-07-01 18:26:19 +053029static constexpr const char* assetIfaceName =
30 "xyz.openbmc_project.Inventory.Decorator.Asset";
Rohit PAIfb64f062025-06-13 18:20:02 +053031static constexpr const char* uuidIfaceName = "xyz.openbmc_project.Common.UUID";
Rohit PAI0ad57102025-06-13 19:29:20 +053032static constexpr const char* revisionIfaceName =
33 "xyz.openbmc_project.Inventory.Decorator.Revision";
Rohit PAI0a888262025-06-11 08:52:29 +053034
35Inventory::Inventory(
36 const std::shared_ptr<sdbusplus::asio::connection>& /*conn*/,
37 sdbusplus::asio::object_server& objectServer,
Rohit PAIada6baa2025-07-01 18:26:19 +053038 const std::string& inventoryName, mctp::MctpRequester& mctpRequester,
39 const gpu::DeviceIdentification deviceTypeIn, const uint8_t eid,
40 boost::asio::io_context& io) :
41 name(escapeName(inventoryName)), mctpRequester(mctpRequester),
42 deviceType(deviceTypeIn), eid(eid), retryTimer(io)
Rohit PAI0a888262025-06-11 08:52:29 +053043{
Rohit PAIada6baa2025-07-01 18:26:19 +053044 std::string path = inventoryPrefix + name;
Rohit PAIfb64f062025-06-13 18:20:02 +053045
Rohit PAIada6baa2025-07-01 18:26:19 +053046 assetIface = objectServer.add_interface(path, assetIfaceName);
47 assetIface->register_property("Manufacturer", std::string("NVIDIA"));
48 // Register properties which need to be fetched from the device
49 registerProperty(gpu::InventoryPropertyId::SERIAL_NUMBER, assetIface,
50 "SerialNumber");
51 registerProperty(gpu::InventoryPropertyId::BOARD_PART_NUMBER, assetIface,
52 "PartNumber");
Rohit PAI0ad57102025-06-13 19:29:20 +053053 registerProperty(gpu::InventoryPropertyId::MARKETING_NAME, assetIface,
54 "Model");
Rohit PAIada6baa2025-07-01 18:26:19 +053055 assetIface->initialize();
56
Rohit PAIfb64f062025-06-13 18:20:02 +053057 uuidInterface = objectServer.add_interface(path, uuidIfaceName);
58 registerProperty(gpu::InventoryPropertyId::DEVICE_GUID, uuidInterface,
59 "UUID");
60 uuidInterface->initialize();
61
Rohit PAI0ad57102025-06-13 19:29:20 +053062 revisionIface = objectServer.add_interface(path, revisionIfaceName);
63 registerProperty(gpu::InventoryPropertyId::DEVICE_PART_NUMBER,
64 revisionIface, "Version");
65 revisionIface->initialize();
66
Rohit PAIada6baa2025-07-01 18:26:19 +053067 // Static properties
Rohit PAI0a888262025-06-11 08:52:29 +053068 if (deviceType == gpu::DeviceIdentification::DEVICE_GPU)
69 {
Rohit PAIada6baa2025-07-01 18:26:19 +053070 acceleratorInterface =
71 objectServer.add_interface(path, acceleratorIfaceName);
72 acceleratorInterface->register_property("Type", std::string("GPU"));
73 acceleratorInterface->initialize();
74 }
Marc Olberdingac920732025-09-28 21:56:54 -070075}
Rohit PAIada6baa2025-07-01 18:26:19 +053076
Marc Olberdingac920732025-09-28 21:56:54 -070077void Inventory::init()
78{
Rohit PAIada6baa2025-07-01 18:26:19 +053079 processNextProperty();
80}
81
82void Inventory::registerProperty(
83 gpu::InventoryPropertyId propertyId,
84 const std::shared_ptr<sdbusplus::asio::dbus_interface>& interface,
85 const std::string& propertyName)
86{
87 if (interface)
88 {
89 interface->register_property(propertyName, std::string{});
90 properties[propertyId] = {interface, propertyName, 0, true};
91 }
92}
93
94void Inventory::processInventoryProperty(gpu::InventoryPropertyId propertyId)
95{
96 auto it = properties.find(propertyId);
97 if (it != properties.end())
98 {
99 markPropertyPending(it);
100 std::optional<gpu::InventoryPropertyId> nextProperty =
101 getNextPendingProperty();
102 if (nextProperty && *nextProperty == propertyId)
Rohit PAI0a888262025-06-11 08:52:29 +0530103 {
Rohit PAIada6baa2025-07-01 18:26:19 +0530104 processNextProperty();
Rohit PAI0a888262025-06-11 08:52:29 +0530105 }
Rohit PAIada6baa2025-07-01 18:26:19 +0530106 }
107}
108
109void Inventory::markPropertyPending(
110 std::unordered_map<gpu::InventoryPropertyId, PropertyInfo>::iterator it)
111{
112 it->second.isPending = true;
113 it->second.retryCount = 0;
114}
115
116void Inventory::markPropertyProcessed(
117 std::unordered_map<gpu::InventoryPropertyId, PropertyInfo>::iterator it)
118{
119 it->second.isPending = false;
120}
121
122std::optional<gpu::InventoryPropertyId> Inventory::getNextPendingProperty()
123 const
124{
125 for (const auto& [propertyId, info] : properties)
126 {
127 if (info.isPending)
128 {
129 return propertyId;
130 }
131 }
132 return std::nullopt;
133}
134
135void Inventory::sendInventoryPropertyRequest(
136 gpu::InventoryPropertyId propertyId)
137{
138 int rc = gpu::encodeGetInventoryInformationRequest(
Marc Olberdingd0125c92025-10-08 14:37:19 -0700139 0, static_cast<uint8_t>(propertyId), requestBuffer);
Rohit PAIada6baa2025-07-01 18:26:19 +0530140 if (rc != 0)
141 {
142 lg2::error(
143 "Failed to encode property ID {PROP_ID} request for {NAME}: rc={RC}",
144 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name, "RC",
145 rc);
146 return;
147 }
148
149 lg2::info(
150 "Sending inventory request for property ID {PROP_ID} to EID {EID} for {NAME}",
151 "PROP_ID", static_cast<uint8_t>(propertyId), "EID", eid, "NAME", name);
152
Marc Olberdingd0125c92025-10-08 14:37:19 -0700153 mctpRequester.sendRecvMsg(
154 eid, requestBuffer,
155 [this, propertyId](const std::error_code& result,
156 std::span<const uint8_t> buffer) {
157 this->handleInventoryPropertyResponse(propertyId, result, buffer);
158 });
Rohit PAIada6baa2025-07-01 18:26:19 +0530159}
160
161void Inventory::handleInventoryPropertyResponse(
Marc Olberdingd0125c92025-10-08 14:37:19 -0700162 gpu::InventoryPropertyId propertyId, const std::error_code& ec,
163 std::span<const uint8_t> buffer)
Rohit PAIada6baa2025-07-01 18:26:19 +0530164{
165 auto it = properties.find(propertyId);
166 if (it == properties.end())
167 {
168 lg2::error("Property ID {PROP_ID} for {NAME} not found", "PROP_ID",
169 static_cast<uint8_t>(propertyId), "NAME", name);
170 processNextProperty();
171 return;
172 }
173
174 bool success = false;
Marc Olberdingd0125c92025-10-08 14:37:19 -0700175 if (!ec)
Rohit PAIada6baa2025-07-01 18:26:19 +0530176 {
177 ocp::accelerator_management::CompletionCode cc{};
178 uint16_t reasonCode = 0;
179 gpu::InventoryValue info;
180 int rc = gpu::decodeGetInventoryInformationResponse(
Marc Olberdingd0125c92025-10-08 14:37:19 -0700181 buffer, cc, reasonCode, propertyId, info);
Rohit PAIada6baa2025-07-01 18:26:19 +0530182
183 lg2::info(
184 "Response for property ID {PROP_ID} from {NAME}, sendRecvMsgResult: {RESULT}, decode_rc: {RC}, completion_code: {CC}, reason_code: {REASON}",
185 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name, "RESULT",
Marc Olberdingd0125c92025-10-08 14:37:19 -0700186 ec.message(), "RC", rc, "CC", static_cast<uint8_t>(cc), "REASON",
187 reasonCode);
Rohit PAIada6baa2025-07-01 18:26:19 +0530188
189 if (rc == 0 &&
Rohit PAIfb64f062025-06-13 18:20:02 +0530190 cc == ocp::accelerator_management::CompletionCode::SUCCESS)
Rohit PAIada6baa2025-07-01 18:26:19 +0530191 {
Rohit PAIfb64f062025-06-13 18:20:02 +0530192 std::string value;
193
194 // Handle different property types based on property ID
195 switch (propertyId)
196 {
197 case gpu::InventoryPropertyId::BOARD_PART_NUMBER:
198 case gpu::InventoryPropertyId::SERIAL_NUMBER:
199 case gpu::InventoryPropertyId::MARKETING_NAME:
200 case gpu::InventoryPropertyId::DEVICE_PART_NUMBER:
201 if (std::holds_alternative<std::string>(info))
202 {
203 value = std::get<std::string>(info);
204 }
205 else
206 {
207 lg2::error(
208 "Property ID {PROP_ID} for {NAME} expected string but got different type",
209 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME",
210 name);
211 break;
212 }
213 break;
214
215 case gpu::InventoryPropertyId::DEVICE_GUID:
216 if (std::holds_alternative<std::vector<uint8_t>>(info))
217 {
218 const auto& guidBytes =
219 std::get<std::vector<uint8_t>>(info);
220 if (guidBytes.size() >= 16)
221 {
222 boost::uuids::uuid uuid;
223 std::copy(guidBytes.begin(), guidBytes.begin() + 16,
224 uuid.begin());
225 value = boost::uuids::to_string(uuid);
226 }
227 else
228 {
229 lg2::error(
230 "Property ID {PROP_ID} for {NAME} GUID size {SIZE} is less than 16 bytes",
231 "PROP_ID", static_cast<uint8_t>(propertyId),
232 "NAME", name, "SIZE", guidBytes.size());
233 break;
234 }
235 }
236 else
237 {
238 lg2::error(
239 "Property ID {PROP_ID} for {NAME} expected vector<uint8_t> but got different type",
240 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME",
241 name);
242 break;
243 }
244 break;
245
246 default:
247 lg2::error("Unsupported property ID {PROP_ID} for {NAME}",
248 "PROP_ID", static_cast<uint8_t>(propertyId),
249 "NAME", name);
250 break;
251 }
252
253 if (!value.empty())
254 {
255 it->second.interface->set_property(it->second.propertyName,
256 value);
257 lg2::info(
258 "Successfully received property ID {PROP_ID} for {NAME} with value: {VALUE}",
259 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name,
260 "VALUE", value);
261 success = true;
262 }
Rohit PAIada6baa2025-07-01 18:26:19 +0530263 }
264 }
265
266 if (!success)
267 {
268 it->second.retryCount++;
269 if (it->second.retryCount >= maxRetryAttempts)
Rohit PAI0a888262025-06-11 08:52:29 +0530270 {
271 lg2::error(
Rohit PAIada6baa2025-07-01 18:26:19 +0530272 "Property ID {PROP_ID} for {NAME} failed after {ATTEMPTS} attempts",
273 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name,
274 "ATTEMPTS", maxRetryAttempts);
275 markPropertyProcessed(it);
Rohit PAI0a888262025-06-11 08:52:29 +0530276 }
Rohit PAIada6baa2025-07-01 18:26:19 +0530277 else
278 {
279 retryTimer.expires_after(retryDelay);
280 retryTimer.async_wait([this](const boost::system::error_code& ec) {
281 if (ec)
282 {
283 lg2::error("Retry timer error for {NAME}: {ERROR}", "NAME",
284 name, "ERROR", ec.message());
285 return;
286 }
287 this->processNextProperty();
288 });
289 return;
290 }
291 }
292 else
293 {
294 markPropertyProcessed(it);
295 }
296
297 processNextProperty();
298}
299
300void Inventory::processNextProperty()
301{
302 std::optional<gpu::InventoryPropertyId> nextProperty =
303 getNextPendingProperty();
304 if (nextProperty)
305 {
306 sendInventoryPropertyRequest(*nextProperty);
307 }
308 else
309 {
310 lg2::info("No pending properties found to process for {NAME}", "NAME",
311 name);
Rohit PAI0a888262025-06-11 08:52:29 +0530312 }
313}