blob: 7a1c3cc41c28562fc0f5d472294d18b6ebf88228 [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>
Rohit PAI0a888262025-06-11 08:52:29 +053019#include <string>
Rohit PAIada6baa2025-07-01 18:26:19 +053020#include <unordered_map>
21#include <variant>
Rohit PAIfb64f062025-06-13 18:20:02 +053022#include <vector>
Rohit PAI0a888262025-06-11 08:52:29 +053023
24constexpr const char* inventoryPrefix = "/xyz/openbmc_project/inventory/";
25constexpr const char* acceleratorIfaceName =
26 "xyz.openbmc_project.Inventory.Item.Accelerator";
Rohit PAIada6baa2025-07-01 18:26:19 +053027static constexpr const char* assetIfaceName =
28 "xyz.openbmc_project.Inventory.Decorator.Asset";
Rohit PAIfb64f062025-06-13 18:20:02 +053029static constexpr const char* uuidIfaceName = "xyz.openbmc_project.Common.UUID";
Rohit PAI0ad57102025-06-13 19:29:20 +053030static constexpr const char* revisionIfaceName =
31 "xyz.openbmc_project.Inventory.Decorator.Revision";
Rohit PAI0a888262025-06-11 08:52:29 +053032
33Inventory::Inventory(
34 const std::shared_ptr<sdbusplus::asio::connection>& /*conn*/,
35 sdbusplus::asio::object_server& objectServer,
Rohit PAIada6baa2025-07-01 18:26:19 +053036 const std::string& inventoryName, mctp::MctpRequester& mctpRequester,
37 const gpu::DeviceIdentification deviceTypeIn, const uint8_t eid,
38 boost::asio::io_context& io) :
39 name(escapeName(inventoryName)), mctpRequester(mctpRequester),
40 deviceType(deviceTypeIn), eid(eid), retryTimer(io)
Rohit PAI0a888262025-06-11 08:52:29 +053041{
Rohit PAIada6baa2025-07-01 18:26:19 +053042 requestBuffer = std::make_shared<InventoryRequestBuffer>();
43 responseBuffer = std::make_shared<InventoryResponseBuffer>();
44
45 std::string path = inventoryPrefix + name;
Rohit PAIfb64f062025-06-13 18:20:02 +053046
Rohit PAIada6baa2025-07-01 18:26:19 +053047 assetIface = objectServer.add_interface(path, assetIfaceName);
48 assetIface->register_property("Manufacturer", std::string("NVIDIA"));
49 // Register properties which need to be fetched from the device
50 registerProperty(gpu::InventoryPropertyId::SERIAL_NUMBER, assetIface,
51 "SerialNumber");
52 registerProperty(gpu::InventoryPropertyId::BOARD_PART_NUMBER, assetIface,
53 "PartNumber");
Rohit PAI0ad57102025-06-13 19:29:20 +053054 registerProperty(gpu::InventoryPropertyId::MARKETING_NAME, assetIface,
55 "Model");
Rohit PAIada6baa2025-07-01 18:26:19 +053056 assetIface->initialize();
57
Rohit PAIfb64f062025-06-13 18:20:02 +053058 uuidInterface = objectServer.add_interface(path, uuidIfaceName);
59 registerProperty(gpu::InventoryPropertyId::DEVICE_GUID, uuidInterface,
60 "UUID");
61 uuidInterface->initialize();
62
Rohit PAI0ad57102025-06-13 19:29:20 +053063 revisionIface = objectServer.add_interface(path, revisionIfaceName);
64 registerProperty(gpu::InventoryPropertyId::DEVICE_PART_NUMBER,
65 revisionIface, "Version");
66 revisionIface->initialize();
67
Rohit PAIada6baa2025-07-01 18:26:19 +053068 // Static properties
Rohit PAI0a888262025-06-11 08:52:29 +053069 if (deviceType == gpu::DeviceIdentification::DEVICE_GPU)
70 {
Rohit PAIada6baa2025-07-01 18:26:19 +053071 acceleratorInterface =
72 objectServer.add_interface(path, acceleratorIfaceName);
73 acceleratorInterface->register_property("Type", std::string("GPU"));
74 acceleratorInterface->initialize();
75 }
76
77 processNextProperty();
78}
79
80void Inventory::registerProperty(
81 gpu::InventoryPropertyId propertyId,
82 const std::shared_ptr<sdbusplus::asio::dbus_interface>& interface,
83 const std::string& propertyName)
84{
85 if (interface)
86 {
87 interface->register_property(propertyName, std::string{});
88 properties[propertyId] = {interface, propertyName, 0, true};
89 }
90}
91
92void Inventory::processInventoryProperty(gpu::InventoryPropertyId propertyId)
93{
94 auto it = properties.find(propertyId);
95 if (it != properties.end())
96 {
97 markPropertyPending(it);
98 std::optional<gpu::InventoryPropertyId> nextProperty =
99 getNextPendingProperty();
100 if (nextProperty && *nextProperty == propertyId)
Rohit PAI0a888262025-06-11 08:52:29 +0530101 {
Rohit PAIada6baa2025-07-01 18:26:19 +0530102 processNextProperty();
Rohit PAI0a888262025-06-11 08:52:29 +0530103 }
Rohit PAIada6baa2025-07-01 18:26:19 +0530104 }
105}
106
107void Inventory::markPropertyPending(
108 std::unordered_map<gpu::InventoryPropertyId, PropertyInfo>::iterator it)
109{
110 it->second.isPending = true;
111 it->second.retryCount = 0;
112}
113
114void Inventory::markPropertyProcessed(
115 std::unordered_map<gpu::InventoryPropertyId, PropertyInfo>::iterator it)
116{
117 it->second.isPending = false;
118}
119
120std::optional<gpu::InventoryPropertyId> Inventory::getNextPendingProperty()
121 const
122{
123 for (const auto& [propertyId, info] : properties)
124 {
125 if (info.isPending)
126 {
127 return propertyId;
128 }
129 }
130 return std::nullopt;
131}
132
133void Inventory::sendInventoryPropertyRequest(
134 gpu::InventoryPropertyId propertyId)
135{
136 int rc = gpu::encodeGetInventoryInformationRequest(
137 0, static_cast<uint8_t>(propertyId), *requestBuffer);
138 if (rc != 0)
139 {
140 lg2::error(
141 "Failed to encode property ID {PROP_ID} request for {NAME}: rc={RC}",
142 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name, "RC",
143 rc);
144 return;
145 }
146
147 lg2::info(
148 "Sending inventory request for property ID {PROP_ID} to EID {EID} for {NAME}",
149 "PROP_ID", static_cast<uint8_t>(propertyId), "EID", eid, "NAME", name);
150
151 mctpRequester.sendRecvMsg(eid, *requestBuffer, *responseBuffer,
152 [this, propertyId](int sendRecvMsgResult) {
153 this->handleInventoryPropertyResponse(
154 propertyId, sendRecvMsgResult);
155 });
156}
157
158void Inventory::handleInventoryPropertyResponse(
159 gpu::InventoryPropertyId propertyId, int sendRecvMsgResult)
160{
161 auto it = properties.find(propertyId);
162 if (it == properties.end())
163 {
164 lg2::error("Property ID {PROP_ID} for {NAME} not found", "PROP_ID",
165 static_cast<uint8_t>(propertyId), "NAME", name);
166 processNextProperty();
167 return;
168 }
169
170 bool success = false;
171 if (sendRecvMsgResult == 0)
172 {
173 ocp::accelerator_management::CompletionCode cc{};
174 uint16_t reasonCode = 0;
175 gpu::InventoryValue info;
176 int rc = gpu::decodeGetInventoryInformationResponse(
177 *responseBuffer, cc, reasonCode, propertyId, info);
178
179 lg2::info(
180 "Response for property ID {PROP_ID} from {NAME}, sendRecvMsgResult: {RESULT}, decode_rc: {RC}, completion_code: {CC}, reason_code: {REASON}",
181 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name, "RESULT",
182 sendRecvMsgResult, "RC", rc, "CC", static_cast<uint8_t>(cc),
183 "REASON", reasonCode);
184
185 if (rc == 0 &&
Rohit PAIfb64f062025-06-13 18:20:02 +0530186 cc == ocp::accelerator_management::CompletionCode::SUCCESS)
Rohit PAIada6baa2025-07-01 18:26:19 +0530187 {
Rohit PAIfb64f062025-06-13 18:20:02 +0530188 std::string value;
189
190 // Handle different property types based on property ID
191 switch (propertyId)
192 {
193 case gpu::InventoryPropertyId::BOARD_PART_NUMBER:
194 case gpu::InventoryPropertyId::SERIAL_NUMBER:
195 case gpu::InventoryPropertyId::MARKETING_NAME:
196 case gpu::InventoryPropertyId::DEVICE_PART_NUMBER:
197 if (std::holds_alternative<std::string>(info))
198 {
199 value = std::get<std::string>(info);
200 }
201 else
202 {
203 lg2::error(
204 "Property ID {PROP_ID} for {NAME} expected string but got different type",
205 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME",
206 name);
207 break;
208 }
209 break;
210
211 case gpu::InventoryPropertyId::DEVICE_GUID:
212 if (std::holds_alternative<std::vector<uint8_t>>(info))
213 {
214 const auto& guidBytes =
215 std::get<std::vector<uint8_t>>(info);
216 if (guidBytes.size() >= 16)
217 {
218 boost::uuids::uuid uuid;
219 std::copy(guidBytes.begin(), guidBytes.begin() + 16,
220 uuid.begin());
221 value = boost::uuids::to_string(uuid);
222 }
223 else
224 {
225 lg2::error(
226 "Property ID {PROP_ID} for {NAME} GUID size {SIZE} is less than 16 bytes",
227 "PROP_ID", static_cast<uint8_t>(propertyId),
228 "NAME", name, "SIZE", guidBytes.size());
229 break;
230 }
231 }
232 else
233 {
234 lg2::error(
235 "Property ID {PROP_ID} for {NAME} expected vector<uint8_t> but got different type",
236 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME",
237 name);
238 break;
239 }
240 break;
241
242 default:
243 lg2::error("Unsupported property ID {PROP_ID} for {NAME}",
244 "PROP_ID", static_cast<uint8_t>(propertyId),
245 "NAME", name);
246 break;
247 }
248
249 if (!value.empty())
250 {
251 it->second.interface->set_property(it->second.propertyName,
252 value);
253 lg2::info(
254 "Successfully received property ID {PROP_ID} for {NAME} with value: {VALUE}",
255 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name,
256 "VALUE", value);
257 success = true;
258 }
Rohit PAIada6baa2025-07-01 18:26:19 +0530259 }
260 }
261
262 if (!success)
263 {
264 it->second.retryCount++;
265 if (it->second.retryCount >= maxRetryAttempts)
Rohit PAI0a888262025-06-11 08:52:29 +0530266 {
267 lg2::error(
Rohit PAIada6baa2025-07-01 18:26:19 +0530268 "Property ID {PROP_ID} for {NAME} failed after {ATTEMPTS} attempts",
269 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name,
270 "ATTEMPTS", maxRetryAttempts);
271 markPropertyProcessed(it);
Rohit PAI0a888262025-06-11 08:52:29 +0530272 }
Rohit PAIada6baa2025-07-01 18:26:19 +0530273 else
274 {
275 retryTimer.expires_after(retryDelay);
276 retryTimer.async_wait([this](const boost::system::error_code& ec) {
277 if (ec)
278 {
279 lg2::error("Retry timer error for {NAME}: {ERROR}", "NAME",
280 name, "ERROR", ec.message());
281 return;
282 }
283 this->processNextProperty();
284 });
285 return;
286 }
287 }
288 else
289 {
290 markPropertyProcessed(it);
291 }
292
293 processNextProperty();
294}
295
296void Inventory::processNextProperty()
297{
298 std::optional<gpu::InventoryPropertyId> nextProperty =
299 getNextPendingProperty();
300 if (nextProperty)
301 {
302 sendInventoryPropertyRequest(*nextProperty);
303 }
304 else
305 {
306 lg2::info("No pending properties found to process for {NAME}", "NAME",
307 name);
Rohit PAI0a888262025-06-11 08:52:29 +0530308 }
309}